15
15
# TASKS
16
16
################################################################################
17
17
18
- def archive_channel_tree (channel_id , tree = 'main' ):
18
+
19
+ def archive_channel_tree (channel_id , tree = "main" ):
19
20
"""
20
21
Convert the `tree`_tree of `channel_id` to JSON and save it to archives dir.
21
22
"""
22
23
channel = Channel .objects .get (id = channel_id )
23
24
# 1. serialize tree
24
- root = getattr (channel , tree + ' _tree' )
25
+ root = getattr (channel , tree + " _tree" )
25
26
tree_serializer = ContentNodeArchiveSerializer (root )
26
27
tree_data = tree_serializer .data
27
28
@@ -31,31 +32,28 @@ def archive_channel_tree(channel_id, tree='main'):
31
32
32
33
# 3. manually transplant attributes from tree root node onto channel node
33
34
# TODO: review if all these are necessay and archive-worthy
34
- channel_data [' children' ] = tree_data [' children' ]
35
- channel_data [' tree_name' ] = tree + ' _tree' # to know what we're archiving
36
- channel_data [' tree_id' ] = tree_data [' tree_id' ] # to know what we're archiving
37
- channel_data [' created' ] = tree_data [' created' ]
38
- channel_data [' modified' ] = tree_data [' modified' ]
39
- channel_data [' extra_fields' ] = tree_data [' extra_fields' ]
40
- channel_data [' publishing' ] = tree_data [' publishing' ]
41
- channel_data [' published' ] = tree_data [' published' ]
42
- channel_data [' complete' ] = tree_data [' complete' ]
43
- channel_data [' changed' ] = tree_data [' changed' ]
44
- channel_data [' freeze_authoring_data' ] = tree_data [' freeze_authoring_data' ]
35
+ channel_data [" children" ] = tree_data [" children" ]
36
+ channel_data [" tree_name" ] = tree + " _tree" # to know what we're archiving
37
+ channel_data [" tree_id" ] = tree_data [" tree_id" ] # to know what we're archiving
38
+ channel_data [" created" ] = tree_data [" created" ]
39
+ channel_data [" modified" ] = tree_data [" modified" ]
40
+ channel_data [" extra_fields" ] = tree_data [" extra_fields" ]
41
+ channel_data [" publishing" ] = tree_data [" publishing" ]
42
+ channel_data [" published" ] = tree_data [" published" ]
43
+ channel_data [" complete" ] = tree_data [" complete" ]
44
+ channel_data [" changed" ] = tree_data [" changed" ]
45
+ channel_data [" freeze_authoring_data" ] = tree_data [" freeze_authoring_data" ]
45
46
46
47
# 4. dict -> json
47
48
tree_data_json_str = json .dumps (channel_data , indent = 4 , ensure_ascii = False )
48
49
49
50
# 5. save dat
50
51
archive_time = datetime .now ().strftime ("%Y-%m-%d__%H%M" )
51
- filename_ext = channel_id + '_' + tree + '_' + archive_time + ' .json'
52
+ filename_ext = channel_id + "_" + tree + "_" + archive_time + " .json"
52
53
save_to_path = tmpcontent_write (filename_ext , tree_data_json_str )
53
54
return save_to_path
54
55
55
56
56
-
57
-
58
-
59
57
# ARCHIVAL SERIALIZERS
60
58
################################################################################
61
59
@@ -69,63 +67,65 @@ def archive_channel_tree(channel_id, tree='main'):
69
67
70
68
NODE_ATTRIBUTES = [
71
69
# ids
72
- ' kind_id' ,
73
- 'id' ,
74
- ' source_domain' ,
75
- ' source_id' ,
76
- ' content_id' ,
77
- ' node_id' ,
70
+ " kind_id" ,
71
+ "id" ,
72
+ " source_domain" ,
73
+ " source_id" ,
74
+ " content_id" ,
75
+ " node_id" ,
78
76
# data
79
- ' title' ,
80
- ' description' ,
81
- ' language' ,
82
- ' author' ,
83
- ' aggregator' ,
84
- ' provider' ,
85
- ' thumbnail_encoding' ,
77
+ " title" ,
78
+ " description" ,
79
+ " language" ,
80
+ " author" ,
81
+ " aggregator" ,
82
+ " provider" ,
83
+ " thumbnail_encoding" ,
86
84
# licensing metadata
87
- ' license_id' ,
88
- ' license_description' ,
89
- ' copyright_holder' ,
85
+ " license_id" ,
86
+ " license_description" ,
87
+ " copyright_holder" ,
90
88
# domain-specific metadata
91
- ' role_visibility' ,
89
+ " role_visibility" ,
92
90
# content provenance
93
- ' original_node_id' ,
94
- ' cloned_source_id' ,
95
- ' original_channel_id' ,
96
- ' source_channel_id' ,
97
- ' original_source_node_id' ,
98
- ' source_node_id' ,
91
+ " original_node_id" ,
92
+ " cloned_source_id" ,
93
+ " original_channel_id" ,
94
+ " source_channel_id" ,
95
+ " original_source_node_id" ,
96
+ " source_node_id" ,
99
97
# workflows
100
- ' publishing' ,
101
- ' published' ,
102
- ' complete' ,
103
- ' changed' ,
104
- ' freeze_authoring_data' , # needed?
98
+ " publishing" ,
99
+ " published" ,
100
+ " complete" ,
101
+ " changed" ,
102
+ " freeze_authoring_data" , # needed?
105
103
# structural
106
- ' parent_id' ,
107
- ' sort_order' ,
104
+ " parent_id" ,
105
+ " sort_order" ,
108
106
# via MPTTModel
109
- 'tree_id' ,
110
- 'level' , # TODO: remove me (info not neeeded)
111
- 'lft' , 'rght' , # TODO: remove me (info not neeeded)
107
+ "tree_id" ,
108
+ "level" , # TODO: remove me (info not neeeded)
109
+ "lft" ,
110
+ "rght" , # TODO: remove me (info not neeeded)
112
111
# timestamps
113
- ' created' ,
114
- ' modified' ,
112
+ " created" ,
113
+ " modified" ,
115
114
# kind-specific extended attributes
116
- ' extra_fields' ,
115
+ " extra_fields" ,
117
116
]
118
117
119
118
NODE_RELATIONS = [
120
- ' children' ,
121
- ' files' ,
122
- ' assessment_items' ,
119
+ " children" ,
120
+ " files" ,
121
+ " assessment_items" ,
123
122
]
124
123
125
124
126
125
# copied from
127
126
# https://github.com/learningequality/studio/blob/develop/contentcuration/contentcuration/viewsets/file.py#L74-L95
128
127
128
+
129
129
class FileArchiveSerializer (FileSerializer ):
130
130
class Meta :
131
131
model = File
@@ -155,6 +155,7 @@ class Meta:
155
155
# copied from
156
156
# https://github.com/learningequality/studio/blob/develop/contentcuration/contentcuration/viewsets/assessmentitem.py#L202-L218
157
157
158
+
158
159
class AssessmentItemArchiveSerializer (AssessmentItemSerializer ):
159
160
class Meta :
160
161
model = AssessmentItem
@@ -175,10 +176,12 @@ class Meta:
175
176
"contentnode" : "contentnode_id" ,
176
177
}
177
178
179
+
178
180
class ContentNodeArchiveSerializer (serializers .ModelSerializer ):
179
181
"""
180
182
This is a read-only content node serializer used for channel archiving.
181
183
"""
184
+
182
185
files = FileArchiveSerializer (many = True )
183
186
assessment_items = AssessmentItemArchiveSerializer (many = True )
184
187
# TODO: finish all fields (reusing existing serializers as much as possible)
@@ -192,50 +195,51 @@ class Meta:
192
195
193
196
def get_fields (self ):
194
197
fields = super (ContentNodeArchiveSerializer , self ).get_fields ()
195
- fields [' children' ] = ContentNodeArchiveSerializer (many = True )
198
+ fields [" children" ] = ContentNodeArchiveSerializer (many = True )
196
199
return fields
197
200
198
201
199
-
200
202
CHANNEL_ATTRIBUTES = [
201
- 'id' ,
202
- ' name' ,
203
- ' description' ,
204
- ' tagline' ,
205
- ' version' ,
206
- ' thumbnail' ,
207
- ' thumbnail_encoding' ,
208
- ' language_id' ,
209
- ' trash_tree_id' ,
210
- ' clipboard_tree_id' ,
211
- ' main_tree_id' ,
212
- ' staging_tree_id' ,
213
- ' chef_tree_id' ,
214
- ' previous_tree_id' ,
215
- ' deleted' ,
216
- ' public' ,
217
- ' preferences' ,
218
- ' content_defaults' ,
219
- ' priority' ,
220
- ' last_published' ,
221
- ' source_url' ,
222
- ' demo_server_url' ,
223
- ' source_id' ,
224
- ' source_domain' ,
225
- ' ricecooker_version' ,
226
- ' published_data' ,
227
- ' icon_encoding' ,
228
- ' total_resource_count' ,
229
- ' published_kind_count' ,
230
- ' published_size' ,
203
+ "id" ,
204
+ " name" ,
205
+ " description" ,
206
+ " tagline" ,
207
+ " version" ,
208
+ " thumbnail" ,
209
+ " thumbnail_encoding" ,
210
+ " language_id" ,
211
+ " trash_tree_id" ,
212
+ " clipboard_tree_id" ,
213
+ " main_tree_id" ,
214
+ " staging_tree_id" ,
215
+ " chef_tree_id" ,
216
+ " previous_tree_id" ,
217
+ " deleted" ,
218
+ " public" ,
219
+ " preferences" ,
220
+ " content_defaults" ,
221
+ " priority" ,
222
+ " last_published" ,
223
+ " source_url" ,
224
+ " demo_server_url" ,
225
+ " source_id" ,
226
+ " source_domain" ,
227
+ " ricecooker_version" ,
228
+ " published_data" ,
229
+ " icon_encoding" ,
230
+ " total_resource_count" ,
231
+ " published_kind_count" ,
232
+ " published_size" ,
231
233
]
232
234
233
235
CHANNEL_RELATIONS = []
234
236
237
+
235
238
class ChannelMetadataArchiveSerializer (serializers .ModelSerializer ):
236
239
"""
237
240
This is a read-only channel metadata serializer used for channel archiving.
238
241
"""
242
+
239
243
# TODO: finish all fields
240
244
# editors?
241
245
# viewers?
@@ -246,25 +250,24 @@ class Meta:
246
250
fields = CHANNEL_ATTRIBUTES + CHANNEL_RELATIONS
247
251
248
252
249
-
250
-
251
253
# SAVE
252
254
################################################################################
253
255
254
- settings_ARCHIVES_ROOT = ' tmpcontent/archives' # TODO: move me to GCP bucket
255
- # i'm thinking archives could be
256
- # a sibling of content/databases
257
- # and content/storage
256
+ settings_ARCHIVES_ROOT = " tmpcontent/archives"
257
+ # TODO: move me to GCP bucket. This dir could be a sibling of content/databases
258
+ # and content/storage, like content/archives/jsontrees/{channel_id}/?/?.json
259
+
258
260
if not os .path .exists (settings_ARCHIVES_ROOT ):
259
261
os .makedirs (settings_ARCHIVES_ROOT , exist_ok = True )
260
262
261
263
262
264
def tmpcontent_write (filename_ext , jsondata ):
263
265
save_to_path = os .path .join (settings_ARCHIVES_ROOT , filename_ext )
264
- with open (save_to_path , 'w' ) as outf :
266
+ with open (save_to_path , "w" ) as outf :
265
267
outf .write (jsondata )
266
268
return save_to_path
267
269
270
+
268
271
# TODO (continued): replace tmpcontent_write; sample code below
269
272
# def write(self, *args, **kwargs):
270
273
# try:
0 commit comments