Skip to content

Commit 92e3c13

Browse files
committed
[Feature] Add Username/Approver to the Command Export
1 parent ae28e90 commit 92e3c13

File tree

4 files changed

+57
-11
lines changed

4 files changed

+57
-11
lines changed

openc3-cosmos-cmd-tlm-api/app/models/streaming_thread.rb

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,17 @@ def handle_message(msg_hash, objects)
159159
if first_object.stream_mode == :RAW
160160
return handle_raw_packet(msg_hash['buffer'], objects, time)
161161
else # @stream_mode == :DECOM or :REDUCED_X
162+
# Parse json_data to extract extra field containing username and other metadata
163+
json_data = msg_hash["json_data"]
164+
extra = nil
165+
if json_data
166+
parsed = JSON.parse(json_data, allow_nan: true, create_additions: true)
167+
if parsed['extra']
168+
extra = JSON.parse(parsed['extra'], allow_nan: true, create_additions: true)
169+
end
170+
end
162171
json_packet = OpenC3::JsonPacket.new(first_object.cmd_or_tlm, first_object.target_name, first_object.packet_name,
163-
time, OpenC3::ConfigParser.handle_true_false(msg_hash["stored"]), msg_hash["json_data"])
172+
time, OpenC3::ConfigParser.handle_true_false(msg_hash["stored"]), json_data, extra: extra)
164173
return handle_json_packet(json_packet, objects)
165174
end
166175
end
@@ -171,6 +180,7 @@ def handle_json_packet(json_packet, objects)
171180
return nil if objects.length <= 0
172181
result = {}
173182
result['__time'] = time.to_nsec_from_epoch
183+
result['__extra'] = json_packet.extra if json_packet.extra
174184
objects.each do |object|
175185
# OpenC3::Logger.debug("item:#{object.item_name} key:#{object.key} type:#{object.value_type}")
176186
if object.item_name

openc3-cosmos-init/plugins/packages/openc3-cosmos-tool-dataextractor/src/tools/DataExtractor/DataExtractor.vue

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@
315315
// Putting large data into Vue data section causes lots of overhead
316316
let dataExtractorRawData = []
317317
318-
import { Cable, OpenC3Api } from '@openc3/js-common/services'
318+
import { Api, Cable, OpenC3Api } from '@openc3/js-common/services'
319319
import {
320320
Config,
321321
OpenConfigDialog,
@@ -391,9 +391,13 @@ export default {
391391
// uniqueIgnoreOptions: ['NO', 'YES'],
392392
cable: new Cable(),
393393
subscription: null,
394+
enterprise: false,
394395
}
395396
},
396397
computed: {
398+
hasCommands: function () {
399+
return this.items.some((item) => item.cmdOrTlm === 'CMD')
400+
},
397401
menus: function () {
398402
return [
399403
{
@@ -566,6 +570,11 @@ export default {
566570
.catch((error) => {
567571
// Do nothing
568572
})
573+
await Api.get('/openc3-api/info').then((response) => {
574+
if (response.data.enterprise) {
575+
this.enterprise = true
576+
}
577+
})
569578
let now = new Date()
570579
this.todaysDate = this.formatDate(now, this.timeZone)
571580
this.startDate = this.formatDate(now - 3600000, this.timeZone) // last hr data
@@ -846,11 +855,14 @@ export default {
846855
for (let packet of data) {
847856
let packetKeys = Object.keys(packet)
848857
packetKeys.forEach(keys.add, keys)
849-
this.itemsReceived += packetKeys.length - 2 // Don't count __type and __time
850-
this.totalItemsReceived += packetKeys.length - 2
858+
// Don't count metadata keys (__type, __time, __extra)
859+
let metadataCount = packetKeys.filter((k) => k.startsWith('__')).length
860+
this.itemsReceived += packetKeys.length - metadataCount
861+
this.totalItemsReceived += packetKeys.length - metadataCount
851862
}
852863
keys.delete('__type')
853864
keys.delete('__time')
865+
keys.delete('__extra')
854866
this.buildHeaders([...keys])
855867
dataExtractorRawData.push(data)
856868
this.progress = Math.ceil(
@@ -874,6 +886,14 @@ export default {
874886
this.columnHeaders.push('TIME')
875887
this.columnHeaders.push('TARGET')
876888
this.columnHeaders.push('PACKET')
889+
// Only add USERNAME and APPROVER columns for command data
890+
if (this.hasCommands) {
891+
this.columnHeaders.push('USERNAME')
892+
// APPROVER is only available in Enterprise
893+
if (this.enterprise) {
894+
this.columnHeaders.push('APPROVER')
895+
}
896+
}
877897
}
878898
itemKeys.forEach((item) => {
879899
if (item.slice(0, 2) === '__') return
@@ -1001,6 +1021,13 @@ export default {
10011021
row[0] = new Date(packet['__time'] / 1000000).toISOString()
10021022
row[1] = targetName
10031023
row[2] = packetName
1024+
// Add username and approver columns for command data
1025+
if (this.hasCommands) {
1026+
row[3] = packet['__extra']?.username || ''
1027+
if (this.enterprise) {
1028+
row[4] = packet['__extra']?.approver || ''
1029+
}
1030+
}
10041031
}
10051032
outputFile.push(row.join(this.delimiter))
10061033
}

openc3/lib/openc3/microservices/interface_microservice.rb

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ def run
8989
InterfaceTopic.receive_commands(@interface, scope: @scope) do |topic, msg_id, msg_hash, _redis|
9090
OpenC3.with_context(msg_hash) do
9191
release_critical = false
92+
critical_model = nil
9293
msgid_seconds_from_epoch = msg_id.split('-')[0].to_i / 1000.0
9394
delta = Time.now.to_f - msgid_seconds_from_epoch
9495
@metric.set(name: 'interface_topic_delta_seconds', value: delta, type: 'gauge', unit: 'seconds', help: 'Delta time between data written to stream and interface cmd start') if @metric
@@ -188,9 +189,9 @@ def run
188189
end
189190
if msg_hash.key?('release_critical')
190191
# Note: intentional fall through below this point
191-
model = CriticalCmdModel.get_model(name: msg_hash['release_critical'], scope: @scope)
192-
if model
193-
msg_hash = model.cmd_hash
192+
critical_model = CriticalCmdModel.get_model(name: msg_hash['release_critical'], scope: @scope)
193+
if critical_model
194+
msg_hash = critical_model.cmd_hash
194195
release_critical = true
195196
else
196197
next "Critical command #{msg_hash['release_critical']} not found"
@@ -279,6 +280,10 @@ def run
279280
command.extra ||= {}
280281
command.extra['cmd_string'] = msg_hash['cmd_string']
281282
command.extra['username'] = msg_hash['username']
283+
# Add approver info if this was a critical command that was approved
284+
if critical_model
285+
command.extra['approver'] = critical_model.approver
286+
end
282287
hazardous, hazardous_description = System.commands.cmd_pkt_hazardous?(command)
283288

284289
# Initial Are you sure? Hazardous check

openc3/python/openc3/microservices/interface_microservice.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ def run(self):
101101
def process_cmd(self, topic, msg_id, msg_hash, _redis):
102102
# OpenC3.with_context(msg_hash) do
103103
release_critical = False
104+
critical_model = None
104105

105106
if msg_hash.get(b"shutdown"):
106107
return "Shutdown"
@@ -218,13 +219,13 @@ def process_cmd(self, topic, msg_id, msg_hash, _redis):
218219
handle_inject_tlm(msg_hash[b"inject_tlm"], self.scope)
219220
return "SUCCESS"
220221
if msg_hash.get(b"release_critical"):
221-
model = CriticalCmdModel.get_model(name=msg_hash[b"release_critical"].decode(), scope=self.scope)
222-
if model is not None:
223-
msg_hash = model.cmd_hash
222+
# Note: intentional fall through below this point
223+
critical_model = CriticalCmdModel.get_model(name=msg_hash[b"release_critical"].decode(), scope=self.scope)
224+
if critical_model is not None:
225+
msg_hash = critical_model.cmd_hash
224226
release_critical = True
225227
else:
226228
return f"Critical command {msg_hash[b'release_critical'].decode()} not found"
227-
return "SUCCESS"
228229
if msg_hash.get(b"target_control"):
229230
try:
230231
params = json.loads(msg_hash[b"target_control"])
@@ -307,6 +308,9 @@ def process_cmd(self, topic, msg_id, msg_hash, _redis):
307308
command.extra = command.extra or {}
308309
command.extra["cmd_string"] = msg_hash[b"cmd_string"].decode()
309310
command.extra["username"] = msg_hash[b"username"].decode()
311+
# Add approver info if this was a critical command that was approved
312+
if critical_model is not None:
313+
command.extra["approver"] = critical_model.approver
310314
hazardous, hazardous_description = System.commands.cmd_pkt_hazardous(command)
311315

312316
if hazardous_check:

0 commit comments

Comments
 (0)