Revision 96efed67
b/snf-astakos-app/astakos/im/models.py | ||
---|---|---|
2091 | 2091 |
|
2092 | 2092 |
### Deactivation calls |
2093 | 2093 |
|
2094 |
def unset_modified(self): |
|
2095 |
self.is_modified = False |
|
2096 |
self.save() |
|
2097 |
|
|
2094 | 2098 |
def deactivate(self): |
2095 | 2099 |
self.deactivation_date = datetime.now() |
2096 | 2100 |
self.is_active = False |
2101 |
self.save() |
|
2097 | 2102 |
|
2098 | 2103 |
def reactivate(self): |
2099 | 2104 |
self.deactivation_date = None |
2100 | 2105 |
self.is_active = True |
2106 |
self.save() |
|
2101 | 2107 |
|
2102 | 2108 |
def terminate(self): |
2103 | 2109 |
self.deactivation_reason = 'TERMINATED' |
... | ... | |
2233 | 2239 |
class ProjectMembershipManager(ForUpdateManager): |
2234 | 2240 |
|
2235 | 2241 |
def any_accepted(self): |
2236 |
q = (Q(state=ProjectMembership.ACCEPTED) | |
|
2237 |
Q(state=ProjectMembership.PROJECT_DEACTIVATED)) |
|
2242 |
q = self.model.Q_ACTUALLY_ACCEPTED |
|
2238 | 2243 |
return self.filter(q) |
2239 | 2244 |
|
2240 | 2245 |
def actually_accepted(self): |
... | ... | |
2258 | 2263 |
LEAVE_REQUESTED = 5 |
2259 | 2264 |
# User deactivation |
2260 | 2265 |
USER_SUSPENDED = 10 |
2261 |
# Project deactivation |
|
2262 |
PROJECT_DEACTIVATED = 100 |
|
2263 | 2266 |
|
2264 | 2267 |
REMOVED = 200 |
2265 | 2268 |
|
... | ... | |
2267 | 2270 |
ACCEPTED, |
2268 | 2271 |
LEAVE_REQUESTED, |
2269 | 2272 |
USER_SUSPENDED, |
2270 |
PROJECT_DEACTIVATED])
|
|
2273 |
]) |
|
2271 | 2274 |
|
2272 | 2275 |
ACCEPTED_STATES = set([ACCEPTED, |
2273 | 2276 |
LEAVE_REQUESTED, |
2274 | 2277 |
USER_SUSPENDED, |
2275 |
PROJECT_DEACTIVATED])
|
|
2278 |
]) |
|
2276 | 2279 |
|
2277 | 2280 |
ACTUALLY_ACCEPTED = set([ACCEPTED, LEAVE_REQUESTED]) |
2278 | 2281 |
|
... | ... | |
2304 | 2307 |
ACCEPTED : _('Accepted'), |
2305 | 2308 |
LEAVE_REQUESTED : _('Leave Requested'), |
2306 | 2309 |
USER_SUSPENDED : _('Suspended'), |
2307 |
PROJECT_DEACTIVATED : _('Accepted'), # sic |
|
2308 | 2310 |
REMOVED : _('Pending removal'), |
2309 | 2311 |
} |
2310 | 2312 |
|
... | ... | |
2313 | 2315 |
ACCEPTED : _('Accepted member'), |
2314 | 2316 |
LEAVE_REQUESTED : _('Requested to leave'), |
2315 | 2317 |
USER_SUSPENDED : _('Suspended member'), |
2316 |
PROJECT_DEACTIVATED : _('Accepted member'), # sic |
|
2317 | 2318 |
REMOVED : _('Pending removal'), |
2318 | 2319 |
} |
2319 | 2320 |
|
... | ... | |
2368 | 2369 |
now = datetime.now() |
2369 | 2370 |
self.acceptance_date = now |
2370 | 2371 |
self._set_history_item(reason='ACCEPT', date=now) |
2371 |
if self.project.is_approved(): |
|
2372 |
self.state = self.ACCEPTED |
|
2373 |
self.is_pending = True |
|
2374 |
else: |
|
2375 |
self.state = self.PROJECT_DEACTIVATED |
|
2376 |
|
|
2372 |
self.state = self.ACCEPTED |
|
2373 |
self.is_pending = True |
|
2377 | 2374 |
self.save() |
2378 | 2375 |
|
2379 | 2376 |
def can_leave(self): |
... | ... | |
2515 | 2512 |
|
2516 | 2513 |
return (sub_list, add_list) |
2517 | 2514 |
|
2515 |
def is_fully_applied(self, project=None): |
|
2516 |
if project is None: |
|
2517 |
project = self.project |
|
2518 |
if project.is_deactivated(): |
|
2519 |
return self.application is None |
|
2520 |
else: |
|
2521 |
return self.application_id == project.application_id |
|
2522 |
|
|
2518 | 2523 |
def set_sync(self): |
2519 | 2524 |
if not self.is_pending: |
2520 | 2525 |
m = _("%s: attempt to sync a non pending membership") % (self,) |
... | ... | |
2523 | 2528 |
state = self.state |
2524 | 2529 |
if state in self.ACTUALLY_ACCEPTED: |
2525 | 2530 |
pending_application = self.pending_application |
2526 |
if pending_application is None: |
|
2527 |
m = _("%s: attempt to sync an empty pending application") % ( |
|
2528 |
self,) |
|
2529 |
raise AssertionError(m) |
|
2530 | 2531 |
|
2531 | 2532 |
self.application = pending_application |
2532 |
self.is_active = True
|
|
2533 |
self.is_active = (self.application is not None)
|
|
2533 | 2534 |
|
2534 | 2535 |
self.pending_application = None |
2535 | 2536 |
self.pending_serial = None |
... | ... | |
2537 | 2538 |
# project.application may have changed in the meantime, |
2538 | 2539 |
# in which case we stay PENDING; |
2539 | 2540 |
# we are safe to check due to select_for_update |
2540 |
if self.application == self.project.application: |
|
2541 |
self.is_pending = False |
|
2542 |
self.save() |
|
2543 |
|
|
2544 |
elif state == self.PROJECT_DEACTIVATED: |
|
2545 |
if self.pending_application: |
|
2546 |
m = _("%s: attempt to sync in state '%s' " |
|
2547 |
"with a pending application") % (self, state) |
|
2548 |
raise AssertionError(m) |
|
2549 |
|
|
2550 |
self.application = None |
|
2551 |
self.is_active = False |
|
2552 |
self.pending_serial = None |
|
2553 |
self.is_pending = False |
|
2541 |
self.is_pending = not self.is_fully_applied() |
|
2554 | 2542 |
self.save() |
2555 | 2543 |
|
2556 | 2544 |
elif state == self.REMOVED: |
... | ... | |
2566 | 2554 |
raise AssertionError(m) |
2567 | 2555 |
|
2568 | 2556 |
state = self.state |
2569 |
if state in [self.ACCEPTED, self.LEAVE_REQUESTED, |
|
2570 |
self.PROJECT_DEACTIVATED, self.REMOVED]: |
|
2557 |
if state in [self.ACCEPTED, self.LEAVE_REQUESTED, self.REMOVED]: |
|
2571 | 2558 |
self.pending_application = None |
2572 | 2559 |
self.pending_serial = None |
2573 | 2560 |
self.save() |
... | ... | |
2620 | 2607 |
qh_ack_serials(list(serials_to_ack)) |
2621 | 2608 |
return len(memberships) |
2622 | 2609 |
|
2610 |
def _pre_sync_projects(projects): |
|
2611 |
for project in projects: |
|
2612 |
objects = project.projectmembership_set |
|
2613 |
memberships = objects.actually_accepted().select_for_update() |
|
2614 |
for membership in memberships: |
|
2615 |
if not membership.is_fully_applied(project): |
|
2616 |
membership.is_pending = True |
|
2617 |
membership.save() |
|
2618 |
|
|
2623 | 2619 |
def pre_sync_projects(sync=True): |
2624 |
ACCEPTED = ProjectMembership.ACCEPTED |
|
2625 |
LEAVE_REQUESTED = ProjectMembership.LEAVE_REQUESTED |
|
2626 |
PROJECT_DEACTIVATED = ProjectMembership.PROJECT_DEACTIVATED |
|
2627 | 2620 |
objs = Project.objects |
2628 | 2621 |
|
2629 | 2622 |
modified = list(objs.modified_projects().select_for_update()) |
2630 |
if sync: |
|
2631 |
for project in modified: |
|
2632 |
objects = project.projectmembership_set |
|
2633 |
|
|
2634 |
memberships = objects.actually_accepted().select_for_update() |
|
2635 |
for membership in memberships: |
|
2636 |
membership.is_pending = True |
|
2637 |
membership.save() |
|
2638 |
|
|
2639 | 2623 |
reactivating = list(objs.reactivating_projects().select_for_update()) |
2640 |
if sync: |
|
2641 |
for project in reactivating: |
|
2642 |
objects = project.projectmembership_set |
|
2643 |
|
|
2644 |
q = objects.filter(state=PROJECT_DEACTIVATED) |
|
2645 |
memberships = q.select_for_update() |
|
2646 |
for membership in memberships: |
|
2647 |
membership.is_pending = True |
|
2648 |
if membership.leave_request_date is None: |
|
2649 |
membership.state = ACCEPTED |
|
2650 |
else: |
|
2651 |
membership.state = LEAVE_REQUESTED |
|
2652 |
membership.save() |
|
2653 |
|
|
2654 | 2624 |
deactivating = list(objs.deactivating_projects().select_for_update()) |
2655 |
if sync: |
|
2656 |
for project in deactivating: |
|
2657 |
objects = project.projectmembership_set |
|
2658 | 2625 |
|
2659 |
# Note: we keep a user-level deactivation |
|
2660 |
# (e.g. USER_SUSPENDED) intact |
|
2661 |
memberships = objects.actually_accepted().select_for_update() |
|
2662 |
for membership in memberships: |
|
2663 |
membership.is_pending = True |
|
2664 |
membership.state = PROJECT_DEACTIVATED |
|
2665 |
membership.save() |
|
2626 |
if sync: |
|
2627 |
_pre_sync_projects(modified) |
|
2628 |
_pre_sync_projects(reactivating) |
|
2629 |
_pre_sync_projects(deactivating) |
|
2666 | 2630 |
|
2667 | 2631 |
# transaction.commit() |
2668 | 2632 |
return (modified, reactivating, deactivating) |
... | ... | |
2694 | 2658 |
logger.warning("Excluded from sync: %s" % uuid) |
2695 | 2659 |
continue |
2696 | 2660 |
|
2697 |
if membership.state in ACTUALLY_ACCEPTED: |
|
2698 |
membership.pending_application = membership.project.application |
|
2661 |
project = membership.project |
|
2662 |
if (membership.state in ACTUALLY_ACCEPTED and |
|
2663 |
not project.is_deactivated()): |
|
2664 |
membership.pending_application = project.application |
|
2699 | 2665 |
|
2700 | 2666 |
membership.pending_serial = serial |
2701 | 2667 |
membership.get_diff_quotas(sub_quota, add_quota) |
... | ... | |
2726 | 2692 |
logger.error("Failed: %s" % r) |
2727 | 2693 |
raise SyncError(m) |
2728 | 2694 |
|
2695 |
def _post_sync_projects(projects, action): |
|
2696 |
for project in projects: |
|
2697 |
objects = project.projectmembership_set |
|
2698 |
memberships = objects.actually_accepted().select_for_update() |
|
2699 |
for membership in memberships: |
|
2700 |
if not membership.is_fully_applied(project): |
|
2701 |
break |
|
2702 |
else: |
|
2703 |
action(project) |
|
2704 |
|
|
2729 | 2705 |
def post_sync_projects(): |
2730 |
PROJECT_DEACTIVATED = ProjectMembership.PROJECT_DEACTIVATED |
|
2731 |
Q_ACTUALLY_ACCEPTED = ProjectMembership.Q_ACTUALLY_ACCEPTED |
|
2732 | 2706 |
objs = Project.objects |
2733 | 2707 |
|
2734 | 2708 |
modified = objs.modified_projects().select_for_update() |
2735 |
for project in modified: |
|
2736 |
objects = project.projectmembership_set |
|
2737 |
q = objects.filter(Q_ACTUALLY_ACCEPTED & Q(is_pending=True)) |
|
2738 |
memberships = list(q.select_for_update()) |
|
2739 |
if not memberships: |
|
2740 |
project.is_modified = False |
|
2741 |
project.save() |
|
2709 |
_post_sync_projects(modified, lambda p: p.unset_modified()) |
|
2742 | 2710 |
|
2743 | 2711 |
reactivating = objs.reactivating_projects().select_for_update() |
2744 |
for project in reactivating: |
|
2745 |
objects = project.projectmembership_set |
|
2746 |
q = objects.filter(Q(state=PROJECT_DEACTIVATED) | Q(is_pending=True)) |
|
2747 |
memberships = list(q.select_for_update()) |
|
2748 |
if not memberships: |
|
2749 |
project.reactivate() |
|
2750 |
project.save() |
|
2712 |
_post_sync_projects(reactivating, lambda p: p.reactivate()) |
|
2751 | 2713 |
|
2752 | 2714 |
deactivating = objs.deactivating_projects().select_for_update() |
2753 |
for project in deactivating: |
|
2754 |
objects = project.projectmembership_set |
|
2755 |
q = objects.filter(Q_ACTUALLY_ACCEPTED | Q(is_pending=True)) |
|
2756 |
memberships = list(q.select_for_update()) |
|
2757 |
if not memberships: |
|
2758 |
project.deactivate() |
|
2759 |
project.save() |
|
2715 |
_post_sync_projects(deactivating, lambda p: p.deactivate()) |
|
2760 | 2716 |
|
2761 | 2717 |
transaction.commit() |
2762 | 2718 |
|
Also available in: Unified diff