58 initial_revision.save() # saving once to set the creation date as we need it to fill the json content |
58 initial_revision.save() # saving once to set the creation date as we need it to fill the json content |
59 if initial_revision.modification_date != initial_revision.creation_date: |
59 if initial_revision.modification_date != initial_revision.creation_date: |
60 initial_revision.modification_date = initial_revision.creation_date |
60 initial_revision.modification_date = initial_revision.creation_date |
61 initial_revision.title = new_renkan_title if new_renkan_title else "Untitled Renkan" |
61 initial_revision.title = new_renkan_title if new_renkan_title else "Untitled Renkan" |
62 if new_renkan_content: |
62 if new_renkan_content: |
63 try: |
63 new_renkan_content_dict = json.loads(new_renkan.validate_json_content(new_renkan_content)) |
64 new_renkan_content_dict = json.loads(new_renkan_content) |
|
65 except ValueError: |
|
66 raise ValidationError("Provided content to create Renkan is not a JSON-serializable") |
|
67 new_renkan_content_dict["created"] = str(initial_revision.creation_date) |
64 new_renkan_content_dict["created"] = str(initial_revision.creation_date) |
68 new_renkan_content_dict["updated"] = str(initial_revision.modification_date) |
65 new_renkan_content_dict["updated"] = str(initial_revision.modification_date) |
69 else: |
66 else: |
70 new_renkan_content_dict = { |
67 new_renkan_content_dict = { |
71 "id": str(new_renkan.renkan_guid), |
68 "id": str(new_renkan.renkan_guid), |
80 "views": [] |
77 "views": [] |
81 } |
78 } |
82 initial_revision.content = json.dumps(new_renkan_content_dict) |
79 initial_revision.content = json.dumps(new_renkan_content_dict) |
83 initial_revision.save() |
80 initial_revision.save() |
84 return new_renkan |
81 return new_renkan |
85 |
82 |
86 |
|
87 class Renkan(models.Model): |
83 class Renkan(models.Model): |
88 |
84 |
89 renkan_guid = models.CharField(max_length=256, default=uuid.uuid4, unique=True, blank=False, null=False) # typically UUID |
85 renkan_guid = models.CharField(max_length=256, default=uuid.uuid4, unique=True, blank=False, null=False) # typically UUID |
90 workspace = models.ForeignKey('Workspace', null=True, blank=True, to_field='workspace_guid') |
86 workspace = models.ForeignKey('Workspace', null=True, blank=True, to_field='workspace_guid') |
91 source_revision = models.ForeignKey('Revision', null=True, blank=True, related_name="renkan_source_revision", to_field='revision_guid', on_delete=models.SET_NULL) |
87 source_revision = models.ForeignKey('Revision', null=True, blank=True, related_name="renkan_source_revision", to_field='revision_guid', on_delete=models.SET_NULL) |
140 revision_to_update = Revision(parent_renkan=self) |
136 revision_to_update = Revision(parent_renkan=self) |
141 revision_to_update.creator = updator |
137 revision_to_update.creator = updator |
142 else: |
138 else: |
143 revision_to_update = Revision.objects.select_for_update().get(revision_guid=self.current_revision.revision_guid) |
139 revision_to_update = Revision.objects.select_for_update().get(revision_guid=self.current_revision.revision_guid) |
144 |
140 |
145 updated_content = content if content else current_revision.content |
141 updated_content = self.validate_json_content(content) if content else current_revision.content |
146 try: |
142 updated_content_dict = json.loads(updated_content) |
147 updated_content_dict = json.loads(updated_content) |
|
148 except ValueError: |
|
149 raise ValidationError(message="Provided content for Renkan is not a JSON-serializable") |
|
150 |
143 |
151 # If title is passed as arg to the method, update the title in the json |
144 # If title is passed as arg to the method, update the title in the json |
152 if title: |
145 if title: |
153 updated_title = title |
146 updated_title = title |
154 updated_content_dict["title"] = title |
147 updated_content_dict["title"] = title |
164 if dt_timestamp == revision_to_update.modification_date: |
157 if dt_timestamp == revision_to_update.modification_date: |
165 revision_to_update.modification_date += datetime.resolution |
158 revision_to_update.modification_date += datetime.resolution |
166 revision_to_update.last_updated_by = updator |
159 revision_to_update.last_updated_by = updator |
167 revision_to_update.save() |
160 revision_to_update.save() |
168 |
161 |
|
162 def validate_json_content(self, content): |
|
163 """ |
|
164 Checks that the json content is valid (keys and structures), raise a ValidationError if format is wrong or value is wrong (for ids), |
|
165 if a key is missing, autocompletes with the empty default value |
|
166 |
|
167 Returns the validated json string |
|
168 """ |
|
169 try: |
|
170 content_to_validate_dict = json.loads(content) |
|
171 except ValueError: |
|
172 raise ValidationError("Provided content to create Renkan is not a JSON-serializable") |
|
173 if "id" not in content_to_validate_dict or content_to_validate_dict["id"] == "" : |
|
174 content_to_validate_dict["id"] = str(self.renkan_guid) |
|
175 if "title" not in content_to_validate_dict: |
|
176 content_to_validate_dict["title"] = "" |
|
177 if "description" not in content_to_validate_dict: |
|
178 content_to_validate_dict["description"] = "" |
|
179 if "created" not in content_to_validate_dict: |
|
180 content_to_validate_dict["description"] = "" |
|
181 if "updated" not in content_to_validate_dict: |
|
182 content_to_validate_dict["description"] = "" |
|
183 expected_workspace_id = str(self.workspace.workspace_guid) if self.workspace is not None else "" |
|
184 if "space_id" not in content_to_validate_dict: |
|
185 content_to_validate_dict["space_id"] = expected_workspace_id |
|
186 if "nodes" not in content_to_validate_dict: |
|
187 content_to_validate_dict["nodes"] = [] |
|
188 if "edges" not in content_to_validate_dict: |
|
189 content_to_validate_dict["edges"] = [] |
|
190 if "views" not in content_to_validate_dict: |
|
191 content_to_validate_dict["views"] = [] |
|
192 if "users" not in content_to_validate_dict: |
|
193 content_to_validate_dict["users"] = [] |
|
194 |
|
195 if type(content_to_validate_dict["nodes"]) is not list: |
|
196 raise ValidationError("Provided content has an invalid 'nodes' key: not a list") |
|
197 if type(content_to_validate_dict["edges"]) is not list: |
|
198 raise ValidationError("Provided content has an invalid 'edges' key: not a list") |
|
199 if type(content_to_validate_dict["views"]) is not list: |
|
200 raise ValidationError("Provided content has an invalid 'views' key: not a list") |
|
201 if type(content_to_validate_dict["users"]) is not list: |
|
202 raise ValidationError("Provided content has an invalid 'users' key: not a list") |
|
203 return json.dumps(content_to_validate_dict) |
|
204 |
169 @transaction.atomic |
205 @transaction.atomic |
170 def delete(self): |
206 def delete(self): |
171 """ |
207 """ |
172 Deleting a renkan also deletes every related revision |
208 Deleting a renkan also deletes every related revision |
173 """ |
209 """ |