53 new_renkan.source_revision = source_revision |
50 new_renkan.source_revision = source_revision |
54 if not title: |
51 if not title: |
55 new_renkan_title = source_revision.title |
52 new_renkan_title = source_revision.title |
56 new_renkan_content = source_revision.content |
53 new_renkan_content = source_revision.content |
57 new_renkan.save() |
54 new_renkan.save() |
|
55 creation_date = timezone.now() |
58 initial_revision = Revision(parent_renkan=new_renkan) |
56 initial_revision = Revision(parent_renkan=new_renkan) |
59 initial_revision.modification_date = timezone.now() |
57 initial_revision.title = new_renkan_title if new_renkan_title else "Untitled Renkan" |
|
58 initial_revision.creation_date = creation_date |
|
59 initial_revision.modification_date = creation_date |
60 initial_revision.creator = creator |
60 initial_revision.creator = creator |
61 initial_revision.last_updated_by = creator |
61 initial_revision.last_updated_by = creator |
62 initial_revision.save() # saving once to set the creation date as we need it to fill the json content |
62 logger.debug("CREATE RENKAN NEW CONTENT %r", new_renkan_content) |
63 if initial_revision.modification_date != initial_revision.creation_date: |
|
64 initial_revision.modification_date = initial_revision.creation_date |
|
65 initial_revision.title = new_renkan_title if new_renkan_title else "Untitled Renkan" |
|
66 if new_renkan_content: |
63 if new_renkan_content: |
67 new_renkan_content_dict = json.loads(new_renkan.validate_json_content(new_renkan_content)) |
64 new_renkan_content_dict = json.loads(new_renkan.validate_json_content(new_renkan_content)) |
68 new_renkan_content_dict["created"] = str(initial_revision.creation_date) |
65 logger.debug("CREATE RENKAN NEW CONTENT AFTER VALIDATE %r", new_renkan_content_dict) |
69 new_renkan_content_dict["updated"] = str(initial_revision.modification_date) |
66 new_renkan_content_dict["created"] = str(creation_date) |
|
67 new_renkan_content_dict["updated"] = str(creation_date) |
70 else: |
68 else: |
71 new_renkan_content_dict = { |
69 new_renkan_content_dict = { |
72 "id": str(new_renkan.renkan_guid), |
70 "id": str(new_renkan.renkan_guid), |
73 "title": initial_revision.title, |
71 "title": initial_revision.title, |
74 "description": "", |
72 "description": "", |
75 "created": str(initial_revision.creation_date), |
73 "created": str(creation_date), |
76 "updated": str(initial_revision.modification_date), |
74 "updated": str(creation_date), |
77 "edges": [], |
75 "edges": [], |
78 "nodes": [], |
76 "nodes": [], |
79 "users": [], |
77 "users": [], |
80 "space_id": new_renkan_workspace_guid, |
78 "space_id": str(new_renkan_workspace_guid), |
81 "views": [] |
79 "views": [] |
82 } |
80 } |
83 initial_revision.content = json.dumps(new_renkan_content_dict) |
81 initial_revision.content = json.dumps(new_renkan_content_dict) |
84 initial_revision.save() |
82 initial_revision.save() |
85 return new_renkan |
83 return new_renkan |
86 |
84 |
87 class Renkan(models.Model): |
85 class Renkan(models.Model): |
88 |
86 |
89 renkan_guid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, blank=False, null=False) |
87 renkan_guid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, blank=False, null=False) |
90 workspace_guid = models.CharField(max_length=256, blank=True, null=True) |
88 workspace = models.ForeignKey('renkanmanager.Workspace', null=True, blank=True, on_delete=models.CASCADE, related_name="renkans") |
91 current_revision_guid = models.CharField(max_length=256, blank=True, null=True) |
89 current_revision = models.ForeignKey('renkanmanager.Revision', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') |
92 source_revision_guid = models.CharField(max_length=256, blank=True, null=True) |
90 source_revision = models.ForeignKey('renkanmanager.Revision', null=True, blank=True, on_delete=models.SET_NULL, related_name='copies') |
93 |
91 |
94 creator = models.ForeignKey(auth_user_model, blank=True, null=True, related_name="renkan_creator") |
92 creator = models.ForeignKey(auth_user_model, blank=True, null=True, related_name="renkan_creator") |
95 creation_date = models.DateTimeField(auto_now_add=True) |
93 creation_date = models.DateTimeField(auto_now_add=True) |
96 state = models.IntegerField(default=1) |
94 state = models.IntegerField(default=1) |
97 |
95 |
98 objects = RenkanManager() |
96 objects = RenkanManager() |
99 |
97 |
100 @property |
98 @property |
101 def revision_count(self): |
99 def revision_count(self): |
102 #TODO: check related object count |
100 return self.revisions.all().count() |
103 return Revision.objects.filter(parent_renkan_guid=self.renkan_guid).count() |
101 |
104 #return Revision.objects.filter(parent_renkan__renkan_guid=self.renkan_guid).count() |
102 @property |
|
103 def workspace_guid(self): |
|
104 return self.workspace and self.workspace.workspace_guid |
|
105 |
|
106 @property |
|
107 def current_revision_guid(self): |
|
108 return self.current_revision and self.current_revision.revision_guid |
|
109 |
|
110 @property |
|
111 def source_revision_guid(self): |
|
112 return self.source_revision and self.source_revision.revision_guid |
|
113 |
105 |
114 |
106 @property |
115 @property |
107 def is_copy(self): |
116 def is_copy(self): |
108 #return bool(self.source_revision) |
117 return bool(self.source_revision) |
109 return bool(self.source_revision_guid) |
|
110 |
|
111 # Current revision object or None if there is none |
|
112 # @property |
|
113 # def current_revision(self): |
|
114 # return Revision.objects.filter(parent_renkan__renkan_guid=self.renkan_guid).order_by('-creation_date').first() |
|
115 |
118 |
116 # Current revision title |
119 # Current revision title |
117 @property |
120 @property |
118 def title(self): |
121 def title(self): |
119 current_revision = Revision.objects.get(revision_guid = self.current_revision_guid) |
122 return self.current_revision and self.current_revision.title or '' |
120 return current_revision.title |
|
121 #TODO: not good -> 2 requests |
|
122 #if self.current_revision: |
|
123 # return self.current_revision.title |
|
124 #else: |
|
125 # return '' |
|
126 |
123 |
127 # Current revision content |
124 # Current revision content |
128 @property |
125 @property |
129 def content(self): |
126 def content(self): |
130 #TODO: not good -> 2 requests |
127 return self.current_revision and self.current_revision.content or '' |
131 current_revision = Revision.objects.get(revision_guid = self.current_revision_guid) |
|
132 return current_revision.content |
|
133 #if self.current_revision: |
|
134 # return self.current_revision.content |
|
135 #else: |
|
136 # return '' |
|
137 |
|
138 def __unicode__(self): |
|
139 return self.renkan_guid |
|
140 |
128 |
141 def __str__(self): |
129 def __str__(self): |
142 return self.renkan_guid |
130 return self.renkan_guid |
143 |
131 |
144 @transaction.atomic |
132 @transaction.atomic |
150 if (not timestamp) or ((self.current_revision is not None) and dateparse.parse_datetime(timestamp) < self.current_revision.modification_date): |
138 if (not timestamp) or ((self.current_revision is not None) and dateparse.parse_datetime(timestamp) < self.current_revision.modification_date): |
151 logger.error("SAVING RENKAN: provided timestamp is %r, which isn't current revision modification_date %r", timestamp, self.current_revision.modification_date) |
139 logger.error("SAVING RENKAN: provided timestamp is %r, which isn't current revision modification_date %r", timestamp, self.current_revision.modification_date) |
152 raise ValidationError(_("Cannot save, provided timestamp is invalid")) |
140 raise ValidationError(_("Cannot save, provided timestamp is invalid")) |
153 else: |
141 else: |
154 dt_timestamp = dateparse.parse_datetime(timestamp) |
142 dt_timestamp = dateparse.parse_datetime(timestamp) |
155 self.save() |
143 logger.debug("SAVE RENKAN create new revision %r", create_new_revision) |
|
144 |
156 if create_new_revision: |
145 if create_new_revision: |
157 revision_to_update = Revision(parent_renkan=self) |
146 revision_to_update = Revision(parent_renkan=self) |
158 revision_to_update.creator = updator |
147 revision_to_update.creator = updator |
159 else: |
148 else: |
160 revision_to_update = Revision.objects.select_for_update().get(revision_guid=self.current_revision.revision_guid) |
149 revision_to_update = Revision.objects.select_for_update().get(id=self.current_revision.id) |
161 |
150 |
162 updated_content = self.validate_json_content(content) if content else current_revision.content |
151 updated_content = self.validate_json_content(content) if content else current_revision.content |
163 updated_content_dict = json.loads(updated_content) |
152 updated_content_dict = json.loads(updated_content) |
164 |
153 |
165 # If title is passed as arg to the method, update the title in the json |
154 # If title is passed as arg to the method, update the title in the json |
221 raise ValidationError("Provided content has an invalid 'views' key: not a list") |
211 raise ValidationError("Provided content has an invalid 'views' key: not a list") |
222 if type(content_to_validate_dict["users"]) is not list: |
212 if type(content_to_validate_dict["users"]) is not list: |
223 raise ValidationError("Provided content has an invalid 'users' key: not a list") |
213 raise ValidationError("Provided content has an invalid 'users' key: not a list") |
224 return json.dumps(content_to_validate_dict) |
214 return json.dumps(content_to_validate_dict) |
225 |
215 |
226 #TODO: |
|
227 # @transaction.atomic |
|
228 # def delete(self): |
|
229 # """ |
|
230 # Deleting a renkan also deletes every related revision |
|
231 # """ |
|
232 # renkan_revisions = Revision.objects.filter(parent_renkan__renkan_guid = self.renkan_guid) |
|
233 # for child_revision in renkan_revisions: |
|
234 # child_revision.delete() |
|
235 # super(Renkan, self).delete() |
|
236 |
|
237 class Meta: |
216 class Meta: |
238 app_label = 'renkanmanager' |
217 app_label = 'renkanmanager' |
239 permissions = ( |
218 permissions = ( |
240 ('view_renkan', 'Can view renkan'), |
219 ('view_renkan', 'Can view renkan'), |
241 ) |
220 ) |
242 |
221 |
243 |
222 |
244 class Revision(models.Model): |
223 class Revision(models.Model): |
245 |
224 |
246 revision_guid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, blank=False, null=False) |
225 revision_guid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True, blank=False, null=False) |
247 parent_renkan_guid = models.CharField(max_length=256) |
226 parent_renkan = models.ForeignKey('renkanmanager.Renkan', on_delete=models.CASCADE, related_name="revisions") |
248 #parent_renkan = models.ForeignKey('Renkan', null=False, blank=False, to_field='renkan_guid') |
|
249 title = models.CharField(max_length=1024, null=True, blank=True) |
227 title = models.CharField(max_length=1024, null=True, blank=True) |
250 content = models.TextField(blank=True, null=True) |
228 content = models.TextField(blank=True, null=True) |
251 creator = models.ForeignKey(auth_user_model, blank=True, null=True, related_name="revision_creator") |
229 creator = models.ForeignKey(auth_user_model, blank=True, null=True, related_name="revision_creator") |
252 last_updated_by = models.ForeignKey(auth_user_model, blank=True, null=True, related_name="revision_last_updated_by") |
230 last_updated_by = models.ForeignKey(auth_user_model, blank=True, null=True, related_name="revision_last_updated_by") |
253 creation_date = models.DateTimeField(auto_now_add=True) |
231 creation_date = models.DateTimeField(auto_now_add=True, editable=False) |
254 modification_date = models.DateTimeField(auto_now=True) |
232 modification_date = models.DateTimeField() |
255 #modification_date = models.DateTimeField() |
233 |
|
234 @property |
|
235 def parent_renkan_guid(self): |
|
236 return self.parent_renkan and self.parent_renkan.renkan_guid |
256 |
237 |
257 @property |
238 @property |
258 def is_current_revision(self): |
239 def is_current_revision(self): |
259 try: |
240 return self == self.parent_renkan.current_revision |
260 parent_project = Renkan.objects.get(renkan_guid=self.parent_renkan_guid) |
|
261 except Renkan.DoesNotExist: # SHOULD NOT HAPPEN! |
|
262 raise Http404 |
|
263 return parent_project.current_revision_guid == self.revision_guid |
|
264 # No need to check if parent_renkan.current_revision is not None, as it won't be if we're calling from a revision |
|
265 #return self.parent_renkan.current_revision.revision_guid == self.revision_guid |
|
266 |
241 |
267 class Meta: |
242 class Meta: |
268 app_label = 'renkanmanager' |
243 app_label = 'renkanmanager' |
|
244 ordering = ['-modification_date'] |
269 permissions = ( |
245 permissions = ( |
270 ('view_revision', 'Can view revision'), |
246 ('view_revision', 'Can view revision'), |
271 ) |
247 ) |
|
248 |
|
249 def __str__(self): |
|
250 return str(self.revision_guid) |