Revision b6fe8bb8
b/snf-astakos-app/astakos/im/functions.py | ||
---|---|---|
66 | 66 |
from astakos.im.notifications import build_notification, NotificationError |
67 | 67 |
from astakos.im.models import ( |
68 | 68 |
AstakosUser, ProjectMembership, ProjectApplication, Project, |
69 |
trigger_sync) |
|
69 |
trigger_sync, PendingMembershipError)
|
|
70 | 70 |
from astakos.im.models import submit_application as models_submit_application |
71 | 71 |
from astakos.im.project_notif import ( |
72 | 72 |
membership_change_notify, |
... | ... | |
434 | 434 |
if isinstance(user, int): |
435 | 435 |
user = get_user_by_id(user) |
436 | 436 |
try: |
437 |
return ProjectMembership.objects.select_for_update().get( |
|
438 |
project=project, |
|
439 |
person=user) |
|
437 |
sfu = ProjectMembership.objects.select_for_update() |
|
438 |
m = sfu.get(project=project, person=user) |
|
439 |
if m.is_pending: |
|
440 |
raise PendingMembershipError() |
|
441 |
return m |
|
440 | 442 |
except ProjectMembership.DoesNotExist: |
441 | 443 |
raise IOError(_(astakos_messages.NOT_MEMBERSHIP_REQUEST)) |
442 | 444 |
|
b/snf-astakos-app/astakos/im/migrations/0053_auto__add_field_project_is_modified__add_field_project_is_active__add_.py | ||
---|---|---|
1 |
# encoding: utf-8 |
|
2 |
import datetime |
|
3 |
from south.db import db |
|
4 |
from south.v2 import SchemaMigration |
|
5 |
from django.db import models |
|
6 |
|
|
7 |
class Migration(SchemaMigration): |
|
8 |
|
|
9 |
def forwards(self, orm): |
|
10 |
|
|
11 |
# Adding field 'Project.is_modified' |
|
12 |
db.add_column('im_project', 'is_modified', self.gf('django.db.models.fields.BooleanField')(default=False, db_index=True), keep_default=False) |
|
13 |
|
|
14 |
# Adding field 'Project.is_active' |
|
15 |
db.add_column('im_project', 'is_active', self.gf('django.db.models.fields.BooleanField')(default=True, db_index=True), keep_default=False) |
|
16 |
|
|
17 |
# Adding field 'ProjectMembership.is_pending' |
|
18 |
db.add_column('im_projectmembership', 'is_pending', self.gf('django.db.models.fields.BooleanField')(default=False, db_index=True), keep_default=False) |
|
19 |
|
|
20 |
# Adding field 'ProjectMembership.is_active' |
|
21 |
db.add_column('im_projectmembership', 'is_active', self.gf('django.db.models.fields.BooleanField')(default=False, db_index=True), keep_default=False) |
|
22 |
|
|
23 |
# Adding index on 'ProjectMembership', fields ['state'] |
|
24 |
db.create_index('im_projectmembership', ['state']) |
|
25 |
|
|
26 |
|
|
27 |
def backwards(self, orm): |
|
28 |
|
|
29 |
# Removing index on 'ProjectMembership', fields ['state'] |
|
30 |
db.delete_index('im_projectmembership', ['state']) |
|
31 |
|
|
32 |
# Deleting field 'Project.is_modified' |
|
33 |
db.delete_column('im_project', 'is_modified') |
|
34 |
|
|
35 |
# Deleting field 'Project.is_active' |
|
36 |
db.delete_column('im_project', 'is_active') |
|
37 |
|
|
38 |
# Deleting field 'ProjectMembership.is_pending' |
|
39 |
db.delete_column('im_projectmembership', 'is_pending') |
|
40 |
|
|
41 |
# Deleting field 'ProjectMembership.is_active' |
|
42 |
db.delete_column('im_projectmembership', 'is_active') |
|
43 |
|
|
44 |
|
|
45 |
models = { |
|
46 |
'auth.group': { |
|
47 |
'Meta': {'object_name': 'Group'}, |
|
48 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
49 |
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), |
|
50 |
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) |
|
51 |
}, |
|
52 |
'auth.permission': { |
|
53 |
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, |
|
54 |
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
|
55 |
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), |
|
56 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
57 |
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) |
|
58 |
}, |
|
59 |
'auth.user': { |
|
60 |
'Meta': {'object_name': 'User'}, |
|
61 |
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
|
62 |
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), |
|
63 |
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
|
64 |
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), |
|
65 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
66 |
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), |
|
67 |
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
68 |
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
69 |
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
|
70 |
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
|
71 |
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), |
|
72 |
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), |
|
73 |
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) |
|
74 |
}, |
|
75 |
'contenttypes.contenttype': { |
|
76 |
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, |
|
77 |
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
|
78 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
79 |
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), |
|
80 |
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) |
|
81 |
}, |
|
82 |
'im.additionalmail': { |
|
83 |
'Meta': {'object_name': 'AdditionalMail'}, |
|
84 |
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}), |
|
85 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
86 |
'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"}) |
|
87 |
}, |
|
88 |
'im.approvalterms': { |
|
89 |
'Meta': {'object_name': 'ApprovalTerms'}, |
|
90 |
'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2013, 1, 10, 14, 25, 18, 997951)', 'db_index': 'True'}), |
|
91 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
92 |
'location': ('django.db.models.fields.CharField', [], {'max_length': '255'}) |
|
93 |
}, |
|
94 |
'im.astakosuser': { |
|
95 |
'Meta': {'object_name': 'AstakosUser', '_ormbases': ['auth.User']}, |
|
96 |
'activation_sent': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), |
|
97 |
'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), |
|
98 |
'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), |
|
99 |
'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), |
|
100 |
'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), |
|
101 |
'date_signed_terms': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), |
|
102 |
'disturbed_quota': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}), |
|
103 |
'email_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
104 |
'has_credits': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
105 |
'has_signed_terms': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
106 |
'invitations': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
|
107 |
'is_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
108 |
'level': ('django.db.models.fields.IntegerField', [], {'default': '4'}), |
|
109 |
'policy': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.AstakosUserQuota']", 'symmetrical': 'False'}), |
|
110 |
'provider': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), |
|
111 |
'third_party_identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), |
|
112 |
'updated': ('django.db.models.fields.DateTimeField', [], {}), |
|
113 |
'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}), |
|
114 |
'uuid': ('django.db.models.fields.CharField', [], {'max_length': '255', 'unique': 'True', 'null': 'True'}) |
|
115 |
}, |
|
116 |
'im.astakosuserauthprovider': { |
|
117 |
'Meta': {'ordering': "('module', 'created')", 'unique_together': "(('identifier', 'module', 'user'),)", 'object_name': 'AstakosUserAuthProvider'}, |
|
118 |
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), |
|
119 |
'affiliation': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}), |
|
120 |
'auth_backend': ('django.db.models.fields.CharField', [], {'default': "'astakos'", 'max_length': '255'}), |
|
121 |
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
|
122 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
123 |
'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), |
|
124 |
'info_data': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}), |
|
125 |
'module': ('django.db.models.fields.CharField', [], {'default': "'local'", 'max_length': '255'}), |
|
126 |
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_providers'", 'to': "orm['im.AstakosUser']"}) |
|
127 |
}, |
|
128 |
'im.astakosuserquota': { |
|
129 |
'Meta': {'unique_together': "(('resource', 'user'),)", 'object_name': 'AstakosUserQuota'}, |
|
130 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
131 |
'limit': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), |
|
132 |
'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"}), |
|
133 |
'uplimit': ('django.db.models.fields.BigIntegerField', [], {'null': 'True'}), |
|
134 |
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"}) |
|
135 |
}, |
|
136 |
'im.emailchange': { |
|
137 |
'Meta': {'object_name': 'EmailChange'}, |
|
138 |
'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}), |
|
139 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
140 |
'new_email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}), |
|
141 |
'requested_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2013, 1, 10, 14, 25, 18, 998740)'}), |
|
142 |
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emailchanges'", 'unique': 'True', 'to': "orm['im.AstakosUser']"}) |
|
143 |
}, |
|
144 |
'im.invitation': { |
|
145 |
'Meta': {'object_name': 'Invitation'}, |
|
146 |
'code': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}), |
|
147 |
'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), |
|
148 |
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
|
149 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
150 |
'inviter': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'invitations_sent'", 'null': 'True', 'to': "orm['im.AstakosUser']"}), |
|
151 |
'is_consumed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
|
152 |
'realname': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
|
153 |
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}) |
|
154 |
}, |
|
155 |
'im.pendingthirdpartyuser': { |
|
156 |
'Meta': {'unique_together': "(('provider', 'third_party_identifier'),)", 'object_name': 'PendingThirdPartyUser'}, |
|
157 |
'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
|
158 |
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), |
|
159 |
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}), |
|
160 |
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
|
161 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
162 |
'info': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}), |
|
163 |
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), |
|
164 |
'provider': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), |
|
165 |
'third_party_identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), |
|
166 |
'token': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), |
|
167 |
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) |
|
168 |
}, |
|
169 |
'im.project': { |
|
170 |
'Meta': {'object_name': 'Project'}, |
|
171 |
'application': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'project'", 'unique': 'True', 'to': "orm['im.ProjectApplication']"}), |
|
172 |
'creation_date': ('django.db.models.fields.DateTimeField', [], {}), |
|
173 |
'deactivation_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), |
|
174 |
'deactivation_reason': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), |
|
175 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
176 |
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}), |
|
177 |
'is_modified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}), |
|
178 |
'last_approval_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), |
|
179 |
'members': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.AstakosUser']", 'through': "orm['im.ProjectMembership']", 'symmetrical': 'False'}), |
|
180 |
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80', 'db_index': 'True'}), |
|
181 |
'state': ('django.db.models.fields.IntegerField', [], {'default': '1', 'db_index': 'True'}) |
|
182 |
}, |
|
183 |
'im.projectapplication': { |
|
184 |
'Meta': {'object_name': 'ProjectApplication'}, |
|
185 |
'applicant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'projects_applied'", 'to': "orm['im.AstakosUser']"}), |
|
186 |
'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), |
|
187 |
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), |
|
188 |
'end_date': ('django.db.models.fields.DateTimeField', [], {}), |
|
189 |
'homepage': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True'}), |
|
190 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
191 |
'issue_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), |
|
192 |
'limit_on_members_number': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}), |
|
193 |
'member_join_policy': ('django.db.models.fields.IntegerField', [], {}), |
|
194 |
'member_leave_policy': ('django.db.models.fields.IntegerField', [], {}), |
|
195 |
'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}), |
|
196 |
'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'projects_owned'", 'to': "orm['im.AstakosUser']"}), |
|
197 |
'precursor_application': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['im.ProjectApplication']", 'unique': 'True', 'null': 'True', 'blank': 'True'}), |
|
198 |
'resource_grants': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.ProjectResourceGrant']", 'blank': 'True'}), |
|
199 |
'start_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), |
|
200 |
'state': ('django.db.models.fields.CharField', [], {'default': "'Pending'", 'max_length': '80'}) |
|
201 |
}, |
|
202 |
'im.projectmembership': { |
|
203 |
'Meta': {'unique_together': "(('person', 'project'),)", 'object_name': 'ProjectMembership'}, |
|
204 |
'acceptance_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'db_index': 'True'}), |
|
205 |
'application': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'memberships'", 'null': 'True', 'to': "orm['im.ProjectApplication']"}), |
|
206 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
207 |
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}), |
|
208 |
'is_pending': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}), |
|
209 |
'leave_request_date': ('django.db.models.fields.DateField', [], {'null': 'True'}), |
|
210 |
'pending_application': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pending_memebrships'", 'null': 'True', 'to': "orm['im.ProjectApplication']"}), |
|
211 |
'pending_serial': ('django.db.models.fields.BigIntegerField', [], {'null': 'True', 'db_index': 'True'}), |
|
212 |
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"}), |
|
213 |
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Project']"}), |
|
214 |
'request_date': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime(2013, 1, 10, 14, 25, 19, 1887)'}), |
|
215 |
'state': ('django.db.models.fields.IntegerField', [], {'default': '0', 'db_index': 'True'}) |
|
216 |
}, |
|
217 |
'im.projectmembershiphistory': { |
|
218 |
'Meta': {'object_name': 'ProjectMembershipHistory'}, |
|
219 |
'date': ('django.db.models.fields.DateField', [], {'default': 'datetime.datetime.now'}), |
|
220 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
221 |
'person': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
|
222 |
'project': ('django.db.models.fields.BigIntegerField', [], {}), |
|
223 |
'reason': ('django.db.models.fields.IntegerField', [], {}), |
|
224 |
'serial': ('django.db.models.fields.BigIntegerField', [], {}) |
|
225 |
}, |
|
226 |
'im.projectresourcegrant': { |
|
227 |
'Meta': {'unique_together': "(('resource', 'project_application'),)", 'object_name': 'ProjectResourceGrant'}, |
|
228 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
229 |
'member_capacity': ('synnefo.lib.db.intdecimalfield.IntDecimalField', [], {'default': '100000000000000000000000000000000L', 'max_digits': '38', 'decimal_places': '0'}), |
|
230 |
'member_export_limit': ('synnefo.lib.db.intdecimalfield.IntDecimalField', [], {'default': '100000000000000000000000000000000L', 'max_digits': '38', 'decimal_places': '0'}), |
|
231 |
'member_import_limit': ('synnefo.lib.db.intdecimalfield.IntDecimalField', [], {'default': '100000000000000000000000000000000L', 'max_digits': '38', 'decimal_places': '0'}), |
|
232 |
'project_application': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.ProjectApplication']", 'null': 'True'}), |
|
233 |
'project_capacity': ('synnefo.lib.db.intdecimalfield.IntDecimalField', [], {'default': '100000000000000000000000000000000L', 'max_digits': '38', 'decimal_places': '0'}), |
|
234 |
'project_export_limit': ('synnefo.lib.db.intdecimalfield.IntDecimalField', [], {'default': '100000000000000000000000000000000L', 'max_digits': '38', 'decimal_places': '0'}), |
|
235 |
'project_import_limit': ('synnefo.lib.db.intdecimalfield.IntDecimalField', [], {'default': '100000000000000000000000000000000L', 'max_digits': '38', 'decimal_places': '0'}), |
|
236 |
'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"}) |
|
237 |
}, |
|
238 |
'im.resource': { |
|
239 |
'Meta': {'unique_together': "(('name', 'service'),)", 'object_name': 'Resource'}, |
|
240 |
'desc': ('django.db.models.fields.TextField', [], {'null': 'True'}), |
|
241 |
'group': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}), |
|
242 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
243 |
'meta': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.ResourceMetadata']", 'symmetrical': 'False'}), |
|
244 |
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}), |
|
245 |
'service': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Service']"}), |
|
246 |
'unit': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}) |
|
247 |
}, |
|
248 |
'im.resourcemetadata': { |
|
249 |
'Meta': {'object_name': 'ResourceMetadata'}, |
|
250 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
251 |
'key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}), |
|
252 |
'value': ('django.db.models.fields.CharField', [], {'max_length': '255'}) |
|
253 |
}, |
|
254 |
'im.serial': { |
|
255 |
'Meta': {'object_name': 'Serial'}, |
|
256 |
'serial': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) |
|
257 |
}, |
|
258 |
'im.service': { |
|
259 |
'Meta': {'ordering': "('order',)", 'object_name': 'Service'}, |
|
260 |
'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}), |
|
261 |
'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), |
|
262 |
'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}), |
|
263 |
'icon': ('django.db.models.fields.FilePathField', [], {'max_length': '100', 'blank': 'True'}), |
|
264 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
265 |
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}), |
|
266 |
'order': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}), |
|
267 |
'url': ('django.db.models.fields.FilePathField', [], {'max_length': '100'}) |
|
268 |
}, |
|
269 |
'im.sessioncatalog': { |
|
270 |
'Meta': {'object_name': 'SessionCatalog'}, |
|
271 |
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
|
272 |
'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}), |
|
273 |
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sessions'", 'null': 'True', 'to': "orm['im.AstakosUser']"}) |
|
274 |
} |
|
275 |
} |
|
276 |
|
|
277 |
complete_apps = ['im'] |
b/snf-astakos-app/astakos/im/models.py | ||
---|---|---|
364 | 364 |
if not m.acceptance_date: |
365 | 365 |
continue |
366 | 366 |
p = m.project |
367 |
if not p.is_active(): |
|
367 |
if not p.is_active_strict():
|
|
368 | 368 |
continue |
369 | 369 |
grants = p.application.projectresourcegrant_set.all() |
370 | 370 |
for g in grants: |
... | ... | |
1286 | 1286 |
except IndexError: |
1287 | 1287 |
return None |
1288 | 1288 |
|
1289 |
def _get_project(self): |
|
1289 |
def _get_project_for_update(self):
|
|
1290 | 1290 |
precursor = self |
1291 | 1291 |
while precursor: |
1292 | 1292 |
try: |
... | ... | |
1318 | 1318 |
raise PermissionDenied(m) # invalid argument |
1319 | 1319 |
|
1320 | 1320 |
now = datetime.now() |
1321 |
project = self._get_project() |
|
1321 |
project = self._get_project_for_update()
|
|
1322 | 1322 |
|
1323 | 1323 |
try: |
1324 | 1324 |
# needs SERIALIZABLE |
... | ... | |
1340 | 1340 |
project.name = new_project_name |
1341 | 1341 |
project.application = self |
1342 | 1342 |
project.last_approval_date = now |
1343 |
project.is_modified = True |
|
1343 | 1344 |
project.save() |
1344 | 1345 |
|
1345 | 1346 |
if new_project: |
1346 | 1347 |
project.add_member(self.owner) |
1347 | 1348 |
|
1348 |
# This will block while syncing, |
|
1349 |
# but unblock before setting the membership state. |
|
1350 |
# See ProjectMembership.set_sync() |
|
1351 |
project.set_membership_pending_sync() |
|
1352 |
|
|
1353 | 1349 |
precursor = self.precursor_application |
1354 | 1350 |
while precursor: |
1355 | 1351 |
precursor.state = self.REPLACED |
... | ... | |
1394 | 1390 |
|
1395 | 1391 |
class ProjectManager(ForUpdateManager): |
1396 | 1392 |
|
1397 |
def deactivating_projects(self): |
|
1398 |
return self.filter(state__gt=Project.ACTIVE) |
|
1399 |
|
|
1400 | 1393 |
def _q_terminated(self): |
1401 |
return Q(state=Project.TERMINATED) | Q(state=Project.TERMINATING)
|
|
1394 |
return Q(state=Project.TERMINATED) |
|
1402 | 1395 |
|
1403 | 1396 |
def terminated_projects(self): |
1404 | 1397 |
q = self._q_terminated() |
... | ... | |
1408 | 1401 |
q = ~self._q_terminated() |
1409 | 1402 |
return self.filter(q) |
1410 | 1403 |
|
1404 |
def terminating_projects(self): |
|
1405 |
q = self._q_terminated() & Q(is_active=True) |
|
1406 |
return self.filter(q) |
|
1407 |
|
|
1408 |
def modified_projects(self): |
|
1409 |
return self.filter(is_modified=True) |
|
1410 |
|
|
1411 |
|
|
1411 | 1412 |
class Project(models.Model): |
1412 | 1413 |
|
1413 | 1414 |
application = models.OneToOneField( |
... | ... | |
1428 | 1429 |
db_index=True, |
1429 | 1430 |
unique=True) |
1430 | 1431 |
|
1431 |
ACTIVE = 1 << 8 |
|
1432 |
TERMINATED = 1 |
|
1433 |
SUSPENDED = 2 |
|
1434 |
|
|
1435 |
INACTIVE = 0 |
|
1436 |
TERMINATING = TERMINATED | ACTIVE |
|
1437 |
SUSPENDING = SUSPENDED | ACTIVE |
|
1432 |
APPROVED = 1 |
|
1433 |
SUSPENDED = 10 |
|
1434 |
TERMINATED = 100 |
|
1438 | 1435 |
|
1439 |
state = models.IntegerField(default=ACTIVE, |
|
1436 |
is_modified = models.BooleanField(default=False, |
|
1437 |
db_index=True) |
|
1438 |
is_active = models.BooleanField(default=True, |
|
1439 |
db_index=True) |
|
1440 |
state = models.IntegerField(default=APPROVED, |
|
1440 | 1441 |
db_index=True) |
1441 | 1442 |
|
1442 | 1443 |
objects = ProjectManager() |
... | ... | |
1446 | 1447 |
|
1447 | 1448 |
__repr__ = __str__ |
1448 | 1449 |
|
1450 |
def is_deactivated(self, reason=None): |
|
1451 |
if reason is not None: |
|
1452 |
return self.state == reason |
|
1449 | 1453 |
|
1450 |
### Internal state manipulation |
|
1451 |
|
|
1452 |
def _active_bit(self): |
|
1453 |
return self.state & self.ACTIVE |
|
1454 |
|
|
1455 |
def is_active_bit(self): |
|
1456 |
return self._active_bit() == self.ACTIVE |
|
1457 |
|
|
1458 |
def is_active_strict(self): |
|
1459 |
return self.state == self.ACTIVE |
|
1460 |
|
|
1461 |
def is_modulo_active(self, s): |
|
1462 |
return self.state & (~self.ACTIVE) == s |
|
1463 |
|
|
1464 |
def set_modulo_active(self, s): |
|
1465 |
self.state = s | self._active_bit() |
|
1466 |
|
|
1467 |
def set_inactive(self): |
|
1468 |
self.state &= (~self.ACTIVE) |
|
1454 |
return self.state != self.APPROVED |
|
1469 | 1455 |
|
1470 | 1456 |
def is_deactivating(self, reason=None): |
1471 |
return (self.is_active_bit() and |
|
1472 |
(self.is_modulo_active(reason) if reason |
|
1473 |
else not self.is_active_strict())) |
|
1457 |
if not self.is_active: |
|
1458 |
return False |
|
1474 | 1459 |
|
1475 |
def is_deactivated_synced(self, reason=None): |
|
1476 |
if reason: |
|
1477 |
return self.state == reason |
|
1478 |
return not self.is_active_bit() |
|
1460 |
return self.is_deactivated(reason) |
|
1479 | 1461 |
|
1480 |
def is_deactivated(self, reason=None): |
|
1481 |
return (self.is_deactivated_synced(reason) or
|
|
1482 |
self.is_deactivating(reason))
|
|
1462 |
def is_deactivated_strict(self, reason=None):
|
|
1463 |
if self.is_active:
|
|
1464 |
return False
|
|
1483 | 1465 |
|
1466 |
return self.is_deactivated(reason) |
|
1484 | 1467 |
|
1485 | 1468 |
### Deactivation calls |
1486 | 1469 |
|
1487 |
def set_deactivation_date(self): |
|
1488 |
self.deactivation_date = datetime.now() |
|
1489 |
|
|
1490 | 1470 |
def deactivate(self): |
1491 |
self.set_deactivation_date()
|
|
1492 |
self.set_inactive()
|
|
1471 |
self.deactivation_date = datetime.now()
|
|
1472 |
self.is_active = False
|
|
1493 | 1473 |
|
1494 | 1474 |
def terminate(self): |
1495 | 1475 |
self.deactivation_reason = 'TERMINATED' |
1496 |
self.set_modulo_active(self.TERMINATED)
|
|
1476 |
self.state = self.TERMINATED
|
|
1497 | 1477 |
self.save() |
1498 | 1478 |
|
1499 | 1479 |
|
... | ... | |
1506 | 1486 |
self.deactivation_date] |
1507 | 1487 |
return any([date > now for date in dates]) |
1508 | 1488 |
|
1509 |
def is_active(self): |
|
1510 |
return self.is_active_strict()
|
|
1489 |
def is_active_strict(self):
|
|
1490 |
return self.is_active and self.state == self.APPROVED
|
|
1511 | 1491 |
|
1512 | 1492 |
@property |
1513 | 1493 |
def is_alive(self): |
1514 |
return self.is_active() |
|
1494 |
return self.is_active_strict()
|
|
1515 | 1495 |
|
1516 | 1496 |
@property |
1517 | 1497 |
def is_terminated(self): |
... | ... | |
1541 | 1521 |
def approved_members(self): |
1542 | 1522 |
return [m.person for m in self.approved_memberships] |
1543 | 1523 |
|
1544 |
def set_membership_pending_sync(self): |
|
1545 |
query = ProjectMembership.query_approved() |
|
1546 |
sfu = self.projectmembership_set.select_for_update() |
|
1547 |
members = sfu.filter(query) |
|
1548 |
|
|
1549 |
for member in members: |
|
1550 |
member.state = member.PENDING |
|
1551 |
member.save() |
|
1552 |
|
|
1553 | 1524 |
def add_member(self, user): |
1554 | 1525 |
""" |
1555 | 1526 |
Raises: |
... | ... | |
1577 | 1548 |
m = ProjectMembership.objects.get(person=user, project=self) |
1578 | 1549 |
m.remove() |
1579 | 1550 |
|
1551 |
|
|
1552 |
class PendingMembershipError(Exception): |
|
1553 |
pass |
|
1554 |
|
|
1555 |
|
|
1580 | 1556 |
class ProjectMembership(models.Model): |
1581 | 1557 |
|
1582 | 1558 |
person = models.ForeignKey(AstakosUser) |
1583 | 1559 |
request_date = models.DateField(default=datetime.now()) |
1584 | 1560 |
project = models.ForeignKey(Project) |
1585 | 1561 |
|
1586 |
state = models.IntegerField(default=0) |
|
1562 |
REQUESTED = 0 |
|
1563 |
ACCEPTED = 1 |
|
1564 |
SUSPENDED = 10 |
|
1565 |
TERMINATED = 100 |
|
1566 |
REMOVED = 200 |
|
1567 |
|
|
1568 |
state = models.IntegerField(default=REQUESTED, |
|
1569 |
db_index=True) |
|
1570 |
is_pending = models.BooleanField(default=False, db_index=True) |
|
1571 |
is_active = models.BooleanField(default=False, db_index=True) |
|
1587 | 1572 |
application = models.ForeignKey( |
1588 | 1573 |
ProjectApplication, |
1589 | 1574 |
null=True, |
... | ... | |
1599 | 1584 |
|
1600 | 1585 |
objects = ForUpdateManager() |
1601 | 1586 |
|
1602 |
REQUESTED = 0 |
|
1603 |
PENDING = 1 |
|
1604 |
ACCEPTED = 2 |
|
1605 |
REMOVING = 3 |
|
1606 |
REMOVED = 4 |
|
1607 |
INACTIVE = 5 |
|
1608 | 1587 |
|
1609 |
APPROVED_SET = [PENDING, ACCEPTED, INACTIVE] |
|
1588 |
def get_combined_state(self): |
|
1589 |
return self.state, self.is_active, self.is_pending |
|
1610 | 1590 |
|
1611 | 1591 |
@classmethod |
1612 | 1592 |
def query_approved(cls): |
1613 |
return (Q(state=cls.PENDING) | |
|
1614 |
Q(state=cls.ACCEPTED) | |
|
1615 |
Q(state=cls.INACTIVE)) |
|
1593 |
return (~Q(state=cls.REQUESTED) & |
|
1594 |
~Q(state=cls.REMOVED)) |
|
1616 | 1595 |
|
1617 | 1596 |
class Meta: |
1618 | 1597 |
unique_together = ("person", "project") |
... | ... | |
1642 | 1621 |
serial = history_item.id |
1643 | 1622 |
|
1644 | 1623 |
def accept(self): |
1624 |
if self.is_pending: |
|
1625 |
m = _("%s: attempt to accept while is pending") % (self,) |
|
1626 |
raise AssertionError(m) |
|
1627 |
|
|
1645 | 1628 |
state = self.state |
1646 | 1629 |
if state != self.REQUESTED: |
1647 | 1630 |
m = _("%s: attempt to accept in state '%s'") % (self, state) |
... | ... | |
1650 | 1633 |
now = datetime.now() |
1651 | 1634 |
self.acceptance_date = now |
1652 | 1635 |
self._set_history_item(reason='ACCEPT', date=now) |
1653 |
self.state = (self.PENDING if self.project.is_active() |
|
1654 |
else self.INACTIVE) |
|
1636 |
if self.project.is_active_strict(): |
|
1637 |
self.state = self.ACCEPTED |
|
1638 |
self.is_pending = True |
|
1639 |
else: |
|
1640 |
self.state = self.TERMINATED |
|
1641 |
|
|
1655 | 1642 |
self.save() |
1656 | 1643 |
|
1657 | 1644 |
def remove(self): |
1645 |
if self.is_pending: |
|
1646 |
m = _("%s: attempt to remove while is pending") % (self,) |
|
1647 |
raise AssertionError(m) |
|
1648 |
|
|
1658 | 1649 |
state = self.state |
1659 |
if state not in [self.ACCEPTED, self.INACTIVE]:
|
|
1650 |
if state not in [self.ACCEPTED, self.TERMINATED]:
|
|
1660 | 1651 |
m = _("%s: attempt to remove in state '%s'") % (self, state) |
1661 | 1652 |
raise AssertionError(m) |
1662 | 1653 |
|
1663 | 1654 |
self._set_history_item(reason='REMOVE') |
1664 |
self.state = self.REMOVING |
|
1655 |
self.state = self.REMOVED |
|
1656 |
self.is_pending = True |
|
1665 | 1657 |
self.save() |
1666 | 1658 |
|
1667 | 1659 |
def reject(self): |
1660 |
if self.is_pending: |
|
1661 |
m = _("%s: attempt to reject while is pending") % (self,) |
|
1662 |
raise AssertionError(m) |
|
1663 |
|
|
1668 | 1664 |
state = self.state |
1669 | 1665 |
if state != self.REQUESTED: |
1670 | 1666 |
m = _("%s: attempt to reject in state '%s'") % (self, state) |
... | ... | |
1675 | 1671 |
self._set_history_item(reason='REJECT') |
1676 | 1672 |
self.delete() |
1677 | 1673 |
|
1678 |
def get_diff_quotas(self, sub_list=None, add_list=None, remove=False):
|
|
1674 |
def get_diff_quotas(self, sub_list=None, add_list=None): |
|
1679 | 1675 |
if sub_list is None: |
1680 | 1676 |
sub_list = [] |
1681 | 1677 |
|
... | ... | |
1697 | 1693 |
import_limit = grant.member_import_limit, |
1698 | 1694 |
export_limit = grant.member_export_limit)) |
1699 | 1695 |
|
1700 |
if not remove: |
|
1701 |
new_grants = self.pending_application.projectresourcegrant_set.all() |
|
1696 |
pending_application = self.pending_application |
|
1697 |
if pending_application is not None: |
|
1698 |
new_grants = pending_application.projectresourcegrant_set.all() |
|
1702 | 1699 |
for new_grant in new_grants: |
1703 | 1700 |
add_append(QuotaLimits( |
1704 | 1701 |
holder = holder, |
... | ... | |
1710 | 1707 |
return (sub_list, add_list) |
1711 | 1708 |
|
1712 | 1709 |
def set_sync(self): |
1710 |
if not self.is_pending: |
|
1711 |
m = _("%s: attempt to sync a non pending membership") % (self,) |
|
1712 |
raise AssertionError(m) |
|
1713 |
|
|
1713 | 1714 |
state = self.state |
1714 |
if state == self.PENDING:
|
|
1715 |
if state == self.ACCEPTED:
|
|
1715 | 1716 |
pending_application = self.pending_application |
1716 | 1717 |
if pending_application is None: |
1717 | 1718 |
m = _("%s: attempt to sync an empty pending application") % ( |
1718 | 1719 |
self,) |
1719 | 1720 |
raise AssertionError(m) |
1721 |
|
|
1720 | 1722 |
self.application = pending_application |
1723 |
self.is_active = True |
|
1724 |
|
|
1721 | 1725 |
self.pending_application = None |
1722 | 1726 |
self.pending_serial = None |
1723 | 1727 |
|
... | ... | |
1725 | 1729 |
# in which case we stay PENDING; |
1726 | 1730 |
# we are safe to check due to select_for_update |
1727 | 1731 |
if self.application == self.project.application: |
1728 |
self.state = self.ACCEPTED
|
|
1732 |
self.is_pending = False
|
|
1729 | 1733 |
self.save() |
1730 |
elif state == self.ACCEPTED: |
|
1734 |
|
|
1735 |
elif state == self.TERMINATED: |
|
1731 | 1736 |
if self.pending_application: |
1732 | 1737 |
m = _("%s: attempt to sync in state '%s' " |
1733 | 1738 |
"with a pending application") % (self, state) |
1734 | 1739 |
raise AssertionError(m) |
1740 |
|
|
1735 | 1741 |
self.application = None |
1736 | 1742 |
self.pending_serial = None |
1737 |
self.state = self.INACTIVE
|
|
1743 |
self.is_pending = False
|
|
1738 | 1744 |
self.save() |
1739 |
elif state == self.REMOVING: |
|
1745 |
|
|
1746 |
elif state == self.REMOVED: |
|
1740 | 1747 |
self.delete() |
1748 |
|
|
1741 | 1749 |
else: |
1742 | 1750 |
m = _("%s: attempt to sync in state '%s'") % (self, state) |
1743 | 1751 |
raise AssertionError(m) |
1744 | 1752 |
|
1745 | 1753 |
def reset_sync(self): |
1754 |
if not self.is_pending: |
|
1755 |
m = _("%s: attempt to reset a non pending membership") % (self,) |
|
1756 |
raise AssertionError(m) |
|
1757 |
|
|
1746 | 1758 |
state = self.state |
1747 |
if state in [self.PENDING, self.ACCEPTED, self.REMOVING]:
|
|
1759 |
if state in [self.ACCEPTED, self.TERMINATED, self.REMOVED]:
|
|
1748 | 1760 |
self.pending_application = None |
1749 | 1761 |
self.pending_serial = None |
1750 | 1762 |
self.save() |
... | ... | |
1782 | 1794 |
qh_ack_serials(list(serials_to_ack)) |
1783 | 1795 |
return len(memberships) |
1784 | 1796 |
|
1785 |
def sync_all_projects(): |
|
1786 |
sync_finish_serials() |
|
1797 |
def pre_sync(): |
|
1798 |
ACCEPTED = ProjectMembership.ACCEPTED |
|
1799 |
TERMINATED = ProjectMembership.TERMINATED |
|
1800 |
psfu = Project.objects.select_for_update() |
|
1801 |
|
|
1802 |
modified = psfu.modified_projects() |
|
1803 |
for project in modified: |
|
1804 |
objects = project.projectmembership_set.select_for_update() |
|
1805 |
|
|
1806 |
memberships = objects.filter(state=ACCEPTED) |
|
1807 |
for membership in memberships: |
|
1808 |
membership.is_pending = True |
|
1809 |
membership.save() |
|
1787 | 1810 |
|
1788 |
PENDING = ProjectMembership.PENDING |
|
1789 |
REMOVING = ProjectMembership.REMOVING |
|
1811 |
terminating = psfu.terminating_projects() |
|
1812 |
for project in terminating: |
|
1813 |
objects = project.projectmembership_set.select_for_update() |
|
1814 |
|
|
1815 |
memberships = objects.filter(state=ACCEPTED) |
|
1816 |
for membership in memberships: |
|
1817 |
membership.is_pending = True |
|
1818 |
membership.state = TERMINATED |
|
1819 |
membership.save() |
|
1820 |
|
|
1821 |
def do_sync(): |
|
1822 |
|
|
1823 |
ACCEPTED = ProjectMembership.ACCEPTED |
|
1790 | 1824 |
objects = ProjectMembership.objects.select_for_update() |
1791 | 1825 |
|
1792 | 1826 |
sub_quota, add_quota = [], [] |
1793 | 1827 |
|
1794 | 1828 |
serial = new_serial() |
1795 | 1829 |
|
1796 |
pending = objects.filter(state=PENDING)
|
|
1830 |
pending = objects.filter(is_pending=True)
|
|
1797 | 1831 |
for membership in pending: |
1798 | 1832 |
|
1799 | 1833 |
if membership.pending_application: |
... | ... | |
1805 | 1839 |
membership, membership.pending_serial) |
1806 | 1840 |
raise AssertionError(m) |
1807 | 1841 |
|
1808 |
membership.pending_application = membership.project.application |
|
1809 |
membership.pending_serial = serial |
|
1810 |
membership.get_diff_quotas(sub_quota, add_quota) |
|
1811 |
membership.save() |
|
1812 |
|
|
1813 |
removing = objects.filter(state=REMOVING) |
|
1814 |
for membership in removing: |
|
1815 |
|
|
1816 |
if membership.pending_application: |
|
1817 |
m = ("%s: impossible: removing pending_application is not None (%s)" |
|
1818 |
% (membership, membership.pending_application)) |
|
1819 |
raise AssertionError(m) |
|
1820 |
if membership.pending_serial: |
|
1821 |
m = "%s: impossible: pending_serial is not None (%s)" % ( |
|
1822 |
membership, membership.pending_serial) |
|
1823 |
raise AssertionError(m) |
|
1842 |
if membership.state == ACCEPTED: |
|
1843 |
membership.pending_application = membership.project.application |
|
1824 | 1844 |
|
1825 | 1845 |
membership.pending_serial = serial |
1826 |
membership.get_diff_quotas(sub_quota, add_quota, remove=True)
|
|
1846 |
membership.get_diff_quotas(sub_quota, add_quota) |
|
1827 | 1847 |
membership.save() |
1828 | 1848 |
|
1829 | 1849 |
transaction.commit() |
... | ... | |
1837 | 1857 |
m = "cannot sync serial: %d" % serial |
1838 | 1858 |
raise RuntimeError(m) |
1839 | 1859 |
|
1840 |
sync_finish_serials([serial]) |
|
1841 |
|
|
1842 |
def sync_deactivating_projects(): |
|
1860 |
return serial |
|
1843 | 1861 |
|
1862 |
def post_sync(): |
|
1844 | 1863 |
ACCEPTED = ProjectMembership.ACCEPTED |
1845 |
PENDING = ProjectMembership.PENDING |
|
1846 |
REMOVING = ProjectMembership.REMOVING |
|
1847 |
|
|
1848 | 1864 |
psfu = Project.objects.select_for_update() |
1849 |
projects = psfu.deactivating_projects() |
|
1850 |
|
|
1851 |
if not projects: |
|
1852 |
return |
|
1853 |
|
|
1854 |
sub_quota, add_quota = [], [] |
|
1855 | 1865 |
|
1856 |
serial = new_serial() |
|
1857 |
|
|
1858 |
for project in projects: |
|
1866 |
modified = psfu.modified_projects() |
|
1867 |
for project in modified: |
|
1859 | 1868 |
objects = project.projectmembership_set.select_for_update() |
1860 |
memberships = objects.filter(Q(state=ACCEPTED) | |
|
1861 |
Q(state=PENDING) | Q(state=REMOVING)) |
|
1862 |
for membership in memberships: |
|
1863 |
if membership.state in (PENDING, REMOVING): |
|
1864 |
m = "cannot sync deactivating project '%s'" % project |
|
1865 |
raise RuntimeError(m) |
|
1866 |
|
|
1867 |
# state == ACCEPTED |
|
1868 |
if membership.pending_application: |
|
1869 |
m = "%s: impossible: pending_application is not None (%s)" % ( |
|
1870 |
membership, membership.pending_application) |
|
1871 |
raise AssertionError(m) |
|
1872 |
if membership.pending_serial: |
|
1873 |
m = "%s: impossible: pending_serial is not None (%s)" % ( |
|
1874 |
membership, membership.pending_serial) |
|
1875 |
raise AssertionError(m) |
|
1876 |
|
|
1877 |
membership.pending_serial = serial |
|
1878 |
membership.get_diff_quotas(sub_quota, add_quota, remove=True) |
|
1879 |
membership.save() |
|
1880 | 1869 |
|
1881 |
transaction.commit() |
|
1882 |
|
|
1883 |
r = qh_add_quota(serial, sub_quota, add_quota) |
|
1884 |
if r: |
|
1885 |
m = "cannot sync serial: %d" % serial |
|
1886 |
raise RuntimeError(m) |
|
1887 |
|
|
1888 |
sync_finish_serials([serial]) |
|
1870 |
memberships = list(objects.filter(state=ACCEPTED, is_pending=True)) |
|
1871 |
if not memberships: |
|
1872 |
project.is_modified = False |
|
1873 |
project.save() |
|
1889 | 1874 |
|
1890 |
# finalize deactivating projects |
|
1891 |
deactivating_projects = psfu.deactivating_projects() |
|
1892 |
for project in deactivating_projects: |
|
1875 |
terminating = psfu.terminating_projects() |
|
1876 |
for project in terminating: |
|
1893 | 1877 |
objects = project.projectmembership_set.select_for_update() |
1878 |
|
|
1894 | 1879 |
memberships = list(objects.filter(Q(state=ACCEPTED) | |
1895 |
Q(state=PENDING) | Q(state=REMOVING)))
|
|
1880 |
Q(is_pending=True)))
|
|
1896 | 1881 |
if not memberships: |
1897 |
project.set_deactivation_date()
|
|
1882 |
project.deactivate()
|
|
1898 | 1883 |
project.save() |
1899 | 1884 |
|
1900 | 1885 |
transaction.commit() |
1901 | 1886 |
|
1902 | 1887 |
def sync_projects(): |
1903 |
sync_all_projects() |
|
1904 |
sync_deactivating_projects() |
|
1888 |
sync_finish_serials() |
|
1889 |
pre_sync() |
|
1890 |
serial = do_sync() |
|
1891 |
sync_finish_serials([serial]) |
|
1892 |
post_sync() |
|
1905 | 1893 |
|
1906 | 1894 |
def trigger_sync(retries=3, retry_wait=1.0): |
1907 | 1895 |
transaction.commit() |
Also available in: Unified diff