Implementation of groups objects and use it to synchronize groups with an advanced method
Benjamin Renard

Benjamin Renard commited on 2014-01-28 01:07:19
Showing 3 changed files, with 236 additions and 18 deletions.

... ...
@@ -5,6 +5,7 @@ import json
5 5
 import logging
6 6
 log = logging.getLogger(__name__)
7 7
 import MySQLdb
8
+from mycoserver import group
8 9
 
9 10
 class DB(object):
10 11
 
... ...
@@ -72,26 +73,17 @@ class DB(object):
72 73
 
73 74
 	def sync_group(self,email,groups):
74 75
 		db_groups=self.get_group(email)
75
-		json_group=json.dumps(groups)
76 76
 		if db_groups!=False:
77
-			log.debug('Database groups : %s' % db_groups)
78
-			log.debug('Provided groups : %s' % groups)
79
-			if 'groups' not in db_groups or db_groups['groups']=={}:
80
-				log.debug('Database group is empty')
81
-				if 'groups' not in groups or groups['groups']=={}:
82
-					log.debug('Database and provided group are empty. Return empty')
83
-					return {'groups': {'groups': {}}}
77
+			db_grouplist=group.GroupList()
78
+			db_grouplist.load(db_groups)
79
+			grouplist=group.GroupList()
80
+			grouplist.load(groups)
81
+			synced_grouplist=db_grouplist.sync(grouplist)
82
+			if self.set_group(email,synced_grouplist.export()):
83
+				log.debug('Groups successfuly synchronized, return result')
84
+				return {'groups': synced_grouplist.export()}
84 85
 			else:
85
-					log.debug('Insert provided groups in database and return it')
86
-					if self.do_sql("INSERT INTO groups (email,groups) VALUES ('%s','%s')" % (email,json_group)):
87
-						return {'groups': groups}
88
-			elif 'groups' not in groups or groups['groups']=={}:
89
-				log.debug('Provide group is empty. Return database groups')
90
-				return {'groups': db_groups}
91
-			else:
92
-				log.debug('Update database with provided group and return it')
93
-				if self.do_sql("UPDATE groups SET groups='%s' WHERE email='%s'" % (json_group,email)):
94
-					return {'groups': groups}
86
+				return {'syncerror': 'Erreur en modifiant les informations de la base de donnees'}
95 87
 		return {'syncerror': 'Erreur inconnu'}
96 88
 
97 89
 	def get_group(self,email):
... ...
@@ -103,3 +95,14 @@ class DB(object):
103 95
 				return {'groups': {}}
104 96
 		else:
105 97
 			return False
98
+
99
+	def set_group(self,email,groups):
100
+		ret=self.select("SELECT groups FROM groups WHERE email='%s'" % email)
101
+		if ret!=False:
102
+			json_groups=json.dumps(groups)
103
+			if len(ret)==1:
104
+				return self.do_sql("UPDATE groups SET groups='%s' WHERE email='%s'" % (json_groups,email))
105
+			else:
106
+				return self.do_sql("INSERT INTO groups (email,groups) VALUES ('%s','%s')" % (email,json_groups))
107
+		else:
108
+			return False
... ...
@@ -0,0 +1,210 @@
1
+#!/usr/bin/python
2
+# -*- coding: utf-8 -*-
3
+
4
+import logging
5
+import urllib
6
+log = logging.getLogger(__name__)
7
+
8
+class GroupList(object):
9
+
10
+  def __init__(self):
11
+    self.groups={}
12
+    self.lastChange=False   
13
+
14
+  def load(self,data):
15
+    if 'lastChange' in data:
16
+      self.lastChange=data['lastChange']
17
+    if 'groups' in data:
18
+      for g in data['groups']:
19
+        self.groups[g]=Group()
20
+        self.groups[g].load(data['groups'][g])
21
+
22
+  def export(self):
23
+    groups={}
24
+    for uuid in self.groups:
25
+      groups[uuid]=self.groups[uuid].export()
26
+
27
+    return {
28
+      'lastChange': self.lastChange,
29
+      'groups': groups
30
+    }
31
+
32
+  def toJSON(self,pretty=False):
33
+    if pretty:
34
+      return json.dumps(self.export(),indent=4, separators=(',', ': '))
35
+    else:
36
+      return json.dumps(self.export())
37
+
38
+  def sync(self,groups):
39
+    ret=GroupList()
40
+    if groups.lastChange<self.lastChange:
41
+      ret.lastChange=self.lastChange
42
+    else:
43
+      ret.lastChange=groups.lastChange
44
+    for uuid in groups.groups:
45
+      if uuid in self.groups:
46
+        ret.groups[uuid]=self.groups[uuid].sync(groups.groups[uuid])
47
+      else:
48
+        ret.groups[uuid]=groups.groups[uuid]
49
+    return ret
50
+
51
+
52
+class Group(object):
53
+
54
+  def __init__(self):
55
+    self.uuid=None
56
+    self.name=None
57
+    self.contributors={}
58
+    self.contributions={}
59
+    self.deletedContributions={}
60
+
61
+  def load(self,data):
62
+    try:
63
+      self.uuid=data['uuid']
64
+      self.name=data['name']
65
+      for email in data['contributors']:
66
+        self.contributors[email]=Contributor()
67
+        self.contributors[email].load(data['contributors'][email])
68
+      for uuid in data['contributions']:
69
+        self.contributions[uuid]=Contribution()
70
+        self.contributions[uuid].load(data['contributions'][uuid])
71
+      if 'deletedContributions' in data:
72
+        for uuid in data['deletedContributions']:
73
+          self.deletedContributions[uuid]=Contribution()
74
+          self.deletedContributions[uuid].load(data['deletedContributions'][uuid])
75
+      return True
76
+    except Exception,e:
77
+      logging.error('Error loading JSON data : %s',e)
78
+      return False
79
+
80
+  def export(self):
81
+    contributors={}
82
+    for email in self.contributors:
83
+      contributors[email]=self.contributors[email].export()
84
+
85
+    contributions={}
86
+    for uuid in self.contributions:
87
+      contributions[uuid]=self.contributions[uuid].export()
88
+
89
+    deletedContributions={}
90
+    for uuid in self.deletedContributions:
91
+      deletedContributions[uuid]=self.deletedContributions[uuid].export()
92
+
93
+    return {
94
+      'uuid': self.uuid,
95
+      'name': self.name,
96
+      'contributors': contributors,
97
+      'contributions': contributions,
98
+      'deletedContributions': deletedContributions
99
+    }
100
+
101
+  def sync(self, group):
102
+    ret=Group()
103
+    ret.uuid=self.uuid
104
+
105
+    # FIXME : Add lastChange on group to permit name choice between to object
106
+    ret.name=group.name
107
+
108
+    ## Contributors
109
+    ret.contributors=self.contributors
110
+    for email in group.contributors:
111
+      if email not in ret.contributors:
112
+        ret.contributors[email]=group.contributors[email]
113
+
114
+    ## Deleted Contributions
115
+    for uuid in self.deletedContributions:
116
+      if uuid in group.deletedContributions:
117
+        ret.deletedContributions[uuid]=self.deletedContributions[uuid].sync(group.deletedContributions[uuid])
118
+      else:
119
+        ret.deletedContributions[uuid]=self.deletedContributions[uuid]
120
+    for uuid in group.deletedContributions:
121
+      if uuid not in ret.deletedContributions:
122
+        ret.deletedContributions[uuid]=group.deletedContributions[uuid]
123
+
124
+    ## Contributions
125
+    for uuid in self.contributions:
126
+      if uuid in group.contributions:
127
+        ret.contributions[uuid]=self.contributions[uuid].sync(group.contributions[uuid])
128
+      elif uuid not in ret.deletedContributions:
129
+        ret.contributions[uuid]=self.contributions[uuid]
130
+      elif self.contributions[uuid].lastChange>ret.deletedContributions[uuid].lastChange:
131
+        ret.contributions[uuid]=self.contributions[uuid]
132
+    for uuid in group.contributions:
133
+      if uuid not in ret.contributions:
134
+        if uuid not in ret.deletedContributions:
135
+          ret.contributions[uuid]=group.contributions[uuid]
136
+        elif group.contributions[uuid].lastChange>ret.deletedContributions[uuid].lastChange:
137
+          ret.contributions[uuid]=group.contributions[uuid]
138
+
139
+    return ret
140
+
141
+
142
+class Contribution(object):
143
+
144
+  def __init__(self):
145
+    self.uuid=None
146
+    self.contributor=None
147
+    self.title=None
148
+    self.cost=None
149
+    self.date=None
150
+    self.lastChange=None
151
+
152
+  def load(self,data):
153
+    self.uuid=data['uuid']
154
+    self.contributor=data['contributor']
155
+    self.title=data['title']
156
+    self.cost=data['cost']
157
+    self.date=data['date']
158
+    self.lastChange=data['lastChange']
159
+
160
+  def export(self):
161
+    return {
162
+      'uuid': self.uuid,
163
+      'contributor': self.contributor,
164
+      'cost': self.cost,
165
+      'title': self.title,
166
+      'date': self.date,
167
+      'lastChange': self.lastChange
168
+    }
169
+
170
+  def sync(self, c):
171
+    if c.lastChange>self.lastChange:
172
+      return c
173
+    else:
174
+      return self
175
+
176
+class Contributor(object):
177
+
178
+  def __init__(self):
179
+    self.name=None
180
+    self.email=None
181
+
182
+  def load(self,data):
183
+    self.name=data['name']
184
+    self.email=data['email']
185
+
186
+  def export(self):
187
+    return {
188
+      'name': self.name,
189
+      'email': self.email
190
+    }
191
+
192
+
193
+if __name__ == '__main__':
194
+  import testdata
195
+  import json
196
+
197
+  data=json.loads(testdata.group_as_json)
198
+  data2=json.loads(testdata.group_as_json2)
199
+
200
+  gl=GroupList()
201
+  gl.load(data2)
202
+
203
+  print gl.toJSON(True)
204
+
205
+  print 'Try sync groups'
206
+  gl2=GroupList()
207
+  gl2.load(data)
208
+  gl_sync=gl.sync(gl2)
209
+  print 'Sync group : %s' % gl_sync
210
+  print gl_sync.toJSON(True)
... ...
@@ -0,0 +1,5 @@
1
+#!/usr/bin/python
2
+
3
+group_as_json="""{"groups":{"7547b547-a3df-40f6-a728-e990ef35c67d":{"uuid":"7547b547-a3df-40f6-a728-e990ef35c67d","name":"test","contributors":{"ben@ben.com":{"name":"Benjamin","email":"ben@ben.com"},"ludo@myco.com":{"name":"Ludovic","email":"ludo@myco.com"}},"contributions":{"4467c88a-f99d-416f-9055-6241441579ed":{"contributor":"ben@ben.com","uuid":"4467c88a-f99d-416f-9055-6241441579ed","cost":14,"title":"test2","date":1390867172110,"lastChange":1390867172117},"78171e1b-8bcf-4614-ac9b-363fd23e3745":{"contributor":"ben@ben.com","uuid":"78171e1b-8bcf-4614-ac9b-363fd23e3745","cost":13,"title":"test","date":1390086000000,"lastChange":1390137335475}},"deletedContributions":{"a370e8a9-ec54-44e8-b6df-22d60d8e6214":{"contributor":"ben@ben.com","cost":12,"date":1390863713090,"lastChange":1390863716422,"title":"test2","uuid":"a370e8a9-ec54-44e8-b6df-22d60d8e6214"}}}}}"""
4
+
5
+group_as_json2="""{"groups":{"7547b547-a3df-40f6-a728-e990ef35c67d":{"uuid":"7547b547-a3df-40f6-a728-e990ef35c67d","name":"test","contributors":{"ben@ben.com":{"name":"Benjamin","email":"ben@ben.com"},"ludo@myco.com":{"name":"Ludovic","email":"ludo@myco.com"}},"contributions":{"78171e1b-8bcf-4614-ac9b-363fd23e3745":{"contributor":"ben@ben.com","uuid":"78171e1b-8bcf-4614-ac9b-363fd23e3745","cost":13,"title":"test","date":1390086000000,"lastChange":1390137335475}},"deletedContributions":{}}}}"""
0 6