Revision 6d583e07

b/Changelog
16 16

  
17 17
* Integrate Pithos tests in continuous integration.
18 18

  
19
Astakos
20
-------
21

  
22
* Changes in project schema:
23

  
24
  * A Project entry is created when submitting an application for a new
25
    project, rather than on approval. Its state is dependent on the state
26
    of its `reference' application (current definition).
27

  
28

  
19 29
Cyclades
20 30
--------
21 31

  
b/snf-astakos-app/astakos/im/functions.py
32 32
# or implied, of GRNET S.A.
33 33

  
34 34
import logging
35
from datetime import datetime
35 36

  
36 37
from django.utils.translation import ugettext as _
37 38
from django.core.mail import send_mail, get_connection
......
39 40
from django.contrib.auth import login as auth_login, logout as auth_logout
40 41
from django.core.exceptions import PermissionDenied
41 42
from django.db.models import Q
42
from django.http import Http404
43 43

  
44 44
from synnefo_branding.utils import render_to_string
45 45

  
......
251 251
POLICIES = [AUTO_ACCEPT_POLICY, MODERATED_POLICY, CLOSED_POLICY]
252 252

  
253 253

  
254
def get_project_by_application_id(project_application_id):
255
    try:
256
        return Project.objects.get(application__id=project_application_id)
257
    except Project.DoesNotExist:
258
        m = (_(astakos_messages.UNKNOWN_PROJECT_APPLICATION_ID) %
259
             project_application_id)
260
        raise IOError(m)
261

  
262

  
263 254
def get_related_project_id(application_id):
264 255
    try:
265 256
        app = ProjectApplication.objects.get(id=application_id)
266
        chain = app.chain
267
        Project.objects.get(id=chain)
268
        return chain
269
    except (ProjectApplication.DoesNotExist, Project.DoesNotExist):
270
        return None
271

  
272

  
273
def get_chain_of_application_id(application_id):
274
    try:
275
        app = ProjectApplication.objects.get(id=application_id)
276
        chain = app.chain
277
        return chain.chain
257
        return app.chain_id
278 258
    except ProjectApplication.DoesNotExist:
279 259
        return None
280 260

  
......
287 267
        raise IOError(m)
288 268

  
289 269

  
290
def get_project_by_name(name):
291
    try:
292
        return Project.objects.get(name=name)
293
    except Project.DoesNotExist:
294
        m = _(astakos_messages.UNKNOWN_PROJECT_ID) % name
295
        raise IOError(m)
296

  
297

  
298 270
def get_chain_for_update(chain_id):
299 271
    try:
300 272
        return Chain.objects.get_for_update(chain=chain_id)
......
646 618
        comments=comments)
647 619

  
648 620
    if precursor is None:
649
        application.chain = new_chain()
621
        chain = new_chain()
622
        application.chain_id = chain.chain
623
        application.save()
624
        Project.objects.create(id=chain.chain, application=application)
650 625
    else:
651 626
        chain = precursor.chain
652 627
        application.chain = chain
653
        objs = ProjectApplication.objects
654
        pending = objs.filter(chain=chain, state=ProjectApplication.PENDING)
628
        application.save()
629
        if chain.application.state != ProjectApplication.APPROVED:
630
            chain.application = application
631
            chain.save()
632

  
633
        pending = ProjectApplication.objects.filter(
634
            chain=chain,
635
            state=ProjectApplication.PENDING).exclude(id=application.id)
655 636
        for app in pending:
656 637
            app.state = ProjectApplication.REPLACED
657 638
            app.save()
658 639

  
659
    application.save()
660 640
    if resource_policies is not None:
661 641
        application.set_resource_policies(resource_policies)
662 642
    logger.info("User %s submitted %s." %
......
715 695

  
716 696

  
717 697
def check_conflicting_projects(application):
718
    try:
719
        project = get_project_by_id(application.chain)
720
    except IOError:
721
        project = None
722

  
698
    project = application.chain
723 699
    new_project_name = application.name
724 700
    try:
725 701
        q = Q(name=new_project_name) & ~Q(state=Project.TERMINATED)
......
732 708
    except Project.DoesNotExist:
733 709
        pass
734 710

  
735
    return project
736

  
737 711

  
738 712
def approve_application(app_id, request_user=None, reason=""):
739 713
    get_chain_of_application_for_update(app_id)
740 714
    application = get_application(app_id)
715
    project = application.chain
741 716

  
742 717
    checkAllowed(application, request_user, admin_only=True)
743 718

  
......
746 721
              (application.id, application.state_display()))
747 722
        raise PermissionDenied(m)
748 723

  
749
    project = check_conflicting_projects(application)
724
    check_conflicting_projects(application)
750 725

  
751 726
    # Pre-lock members and owner together in order to impose an ordering
752 727
    # on locking users
753
    members = members_to_sync(project) if project is not None else []
728
    members = members_to_sync(project)
754 729
    uids_to_sync = [member.id for member in members]
755 730
    owner = application.owner
756 731
    uids_to_sync.append(owner.id)
......
758 733

  
759 734
    qh_release_pending_app(owner, locked=True)
760 735
    application.approve(reason)
736
    project.application = application
737
    project.name = application.name
738
    project.save()
739
    if project.is_deactivated():
740
        project.resume()
761 741
    qh_sync_locked_users(members)
762 742
    logger.info("%s has been approved." % (application.log_display))
763 743
    application_approve_notify(application)
......
813 793
    logger.info("%s has been unsuspended." % (project))
814 794

  
815 795

  
816
def get_by_chain_or_404(chain_id):
817
    try:
818
        project = Project.objects.get(id=chain_id)
819
        application = project.application
820
        return project, application
821
    except:
822
        application = ProjectApplication.objects.latest_of_chain(chain_id)
823
        if application is None:
824
            raise Http404
825
        else:
826
            return None, application
827

  
828

  
829 796
def _partition_by(f, l):
830 797
    d = {}
831 798
    for x in l:
b/snf-astakos-app/astakos/im/management/commands/project-list.py
35 35

  
36 36
from snf_django.management.commands import SynnefoCommand, CommandError
37 37

  
38
from astakos.im.models import Chain
38
from astakos.im.models import Project
39
from django.db.models import Q
39 40
from snf_django.management import utils
40 41
from ._common import is_uuid, is_email
41 42

  
......
107 108

  
108 109
    def handle(self, *args, **options):
109 110

  
110
        chain_dict = Chain.objects.all_full_state()
111
        flt = Q()
112
        owner = options['owner']
113
        if owner:
114
            flt &= filter_by_owner(owner)
111 115

  
112
        if not options['all']:
113
            f_states = []
114
            if options['new']:
115
                f_states.append(Chain.PENDING)
116
            if options['modified']:
117
                f_states += Chain.MODIFICATION_STATES
118
            if options['pending']:
119
                f_states.append(Chain.PENDING)
120
                f_states += Chain.MODIFICATION_STATES
121
            if options['skip']:
122
                if not f_states:
123
                    f_states = Chain.RELEVANT_STATES
124

  
125
            if f_states:
126
                chain_dict = filter_by(in_states(f_states), chain_dict)
127

  
128
            name = options['name']
129
            if name:
130
                chain_dict = filter_by(is_name(name), chain_dict)
131

  
132
            owner = options['owner']
133
            if owner:
134
                chain_dict = filter_by(is_owner(owner), chain_dict)
116
        name = options['name']
117
        if name:
118
            flt &= filter_by_name(name)
135 119

  
136
        labels = ('ProjID', 'Name', 'Owner', 'Email', 'Status', 'AppID')
120
        chains = Project.objects.all_with_pending(flt)
137 121

  
138
        info = chain_info(chain_dict)
122
        if not options['all']:
123
            if options['skip']:
124
                pred = lambda c: (
125
                    c[0].overall_state() not in Project.SKIP_STATES
126
                    or c[1] is not None)
127
                chains = filter_preds([pred], chains)
128

  
129
            preds = []
130
            if options['new'] or options['pending']:
131
                preds.append(
132
                    lambda c: c[0].overall_state() == Project.O_PENDING)
133
            if options['modified'] or options['pending']:
134
                preds.append(
135
                    lambda c: c[0].overall_state() != Project.O_PENDING
136
                    and c[1] is not None)
137

  
138
            if preds:
139
                chains = filter_preds(preds, chains)
140

  
141
        labels = ('ProjID', 'Name', 'Owner', 'Email', 'Status',
142
                  'Pending AppID')
143

  
144
        info = chain_info(chains)
139 145
        utils.pprint_table(self.stdout, info, labels,
140 146
                           options["output_format"])
141 147

  
142 148

  
143
def is_name(name):
144
    def f(state, project, app):
145
        n = project.application.name if project else app.name
146
        return name == n
147
    return f
148

  
149

  
150
def in_states(states):
151
    def f(state, project, app):
152
        return state in states
153
    return f
149
def filter_preds(preds, chains):
150
    return [c for c in chains
151
            if any(map(lambda f: f(c), preds))]
154 152

  
155 153

  
156
def is_owner(s):
157
    def f(state, project, app):
158
        owner = app.owner
159
        if is_email(s):
160
            return owner.email == s
161
        if is_uuid(s):
162
            return owner.uuid == s
163
        raise CommandError("Expecting either email or uuid.")
164
    return f
154
def filter_by_name(name):
155
    return Q(application__name=name)
165 156

  
166 157

  
167
def filter_by(f, chain_dict):
168
    d = {}
169
    for chain, tpl in chain_dict.iteritems():
170
        if f(*tpl):
171
            d[chain] = tpl
172
    return d
158
def filter_by_owner(s):
159
    if is_email(s):
160
        return Q(application__owner__email=s)
161
    if is_uuid(s):
162
        return Q(application__owner__uuid=s)
163
    raise CommandError("Expecting either email or uuid.")
173 164

  
174 165

  
175
def chain_info(chain_dict):
166
def chain_info(chains):
176 167
    l = []
177
    for chain, (state, project, app) in chain_dict.iteritems():
178
        status = Chain.state_display(state)
179
        if state in Chain.PENDING_STATES:
180
            appid = str(app.id)
181
        else:
182
            appid = ""
183

  
184
        t = (chain,
185
             project.application.name if project else app.name,
186
             app.owner.realname,
187
             app.owner.email,
168
    for project, pending_app in chains:
169
        status = project.state_display()
170
        pending_appid = pending_app.id if pending_app is not None else ""
171
        application = project.application
172

  
173
        t = (project.pk,
174
             application.name,
175
             application.owner.realname,
176
             application.owner.email,
188 177
             status,
189
             appid,
178
             pending_appid,
190 179
             )
191 180
        l.append(t)
192 181
    return l
b/snf-astakos-app/astakos/im/management/commands/project-show.py
37 37
from synnefo.lib.ordereddict import OrderedDict
38 38
from snf_django.management.commands import SynnefoCommand
39 39
from snf_django.management import utils
40
from astakos.im.models import Chain, ProjectApplication
40
from astakos.im.models import ProjectApplication, Project
41 41
from ._common import show_resource_value, style_options, check_style
42 42

  
43 43

  
......
93 93
            app = get_app(id_)
94 94
            self.print_app(app)
95 95
        else:
96
            state, project, app = get_chain_state(id_)
97
            self.print_project(state, project, app)
96
            project, pending_app = get_chain_state(id_)
97
            self.print_project(project, pending_app)
98 98
            if show_members and project is not None:
99 99
                self.stdout.write("\n")
100 100
                fields, labels = members_fields(project)
101 101
                self.pprint_table(fields, labels, title="Members")
102
            if show_pending and state in Chain.PENDING_STATES:
102
            if show_pending and pending_app is not None:
103 103
                self.stdout.write("\n")
104
                self.print_app(app)
104
                self.print_app(pending_app)
105 105

  
106 106
    def pprint_dict(self, d, vertical=True):
107 107
        utils.pprint_table(self.stdout, [d.values()], d.keys(),
......
116 116
        self.pprint_dict(app_info)
117 117
        self.print_resources(app)
118 118

  
119
    def print_project(self, state, project, app):
119
    def print_project(self, project, app):
120 120
        if project is None:
121 121
            self.print_app(app)
122 122
        else:
123
            self.pprint_dict(project_fields(state, project, app))
123
            self.pprint_dict(project_fields(project, app))
124 124
            self.print_resources(project.application)
125 125

  
126 126
    def print_resources(self, app):
......
139 139

  
140 140
def get_chain_state(project_id):
141 141
    try:
142
        chain = Chain.objects.get(chain=project_id)
143
        return chain.full_state()
144
    except Chain.DoesNotExist:
142
        chain = Project.objects.get(id=project_id)
143
        return chain, chain.last_pending_application()
144
    except Project.DoesNotExist:
145 145
        raise CommandError("Project with id %s not found." % project_id)
146 146

  
147 147

  
148
def chain_fields(state, project, app):
149
    if project is not None:
150
        return project_fields(state, project, app)
151
    else:
152
        return app_fields(app)
153

  
154

  
155 148
def resource_fields(app, style):
156 149
    labels = ('name', 'description', 'max per member')
157 150
    policies = app.projectresourcegrant_set.all()
......
170 163
    mem_limit_show = mem_limit if mem_limit is not None else "unlimited"
171 164

  
172 165
    d = OrderedDict([
173
        ('project id', app.chain),
166
        ('project id', app.chain_id),
174 167
        ('application id', app.id),
175 168
        ('name', app.name),
176 169
        ('status', app.state_display()),
......
190 183
    return d
191 184

  
192 185

  
193
def project_fields(s, project, last_app):
186
def project_fields(project, pending_app):
194 187
    app = project.application
195 188

  
196 189
    d = OrderedDict([
197 190
        ('project id', project.id),
198 191
        ('application id', app.id),
199 192
        ('name', app.name),
200
        ('status', Chain.state_display(s)),
193
        ('status', project.state_display()),
201 194
    ])
202
    if s in Chain.PENDING_STATES:
203
        d.update([('pending application', last_app.id)])
195
    if pending_app is not None:
196
        d.update([('pending application', pending_app.id)])
204 197

  
205 198
    d.update([('owner', app.owner),
206 199
              ('applicant', app.applicant),
b/snf-astakos-app/astakos/im/management/commands/user-show.py
34 34
from django.core.management.base import CommandError
35 35
from optparse import make_option
36 36

  
37
from astakos.im.models import AstakosUser, get_latest_terms, Chain
37
from django.db.models import Q
38
from astakos.im.models import AstakosUser, get_latest_terms, Project
38 39
from astakos.im.quotas import list_user_quotas
39 40

  
40 41
from synnefo.lib.ordereddict import OrderedDict
......
166 167

  
167 168

  
168 169
def ownerships(user):
169
    chain_dict = Chain.objects.all_full_state()
170
    chain_dict = filter_by(is_owner(user), chain_dict)
171
    return chain_info(chain_dict)
170
    chains = Project.objects.all_with_pending(Q(application__owner=user))
171
    return chain_info(chains)
172 172

  
173 173

  
174
def is_owner(user):
175
    def f(state, project, app):
176
        return user == app.owner
177
    return f
178

  
179

  
180
def filter_by(f, chain_dict):
181
    d = {}
182
    for chain, tpl in chain_dict.iteritems():
183
        if f(*tpl):
184
            d[chain] = tpl
185
    return d
186

  
187

  
188
def chain_info(chain_dict):
174
def chain_info(chains):
189 175
    labels = ('project id', 'project name', 'status', 'pending app id')
190 176
    l = []
191
    for chain, (state, project, app) in chain_dict.iteritems():
192
        status = Chain.state_display(state)
193
        if state in Chain.PENDING_STATES:
194
            appid = str(app.id)
195
        else:
196
            appid = ""
177
    for project, pending_app in chains:
178
        status = project.state_display()
179
        pending_appid = pending_app.id if pending_app is not None else ""
180
        application = project.application
197 181

  
198
        t = (chain,
199
             project.application.name if project else app.name,
182
        t = (project.pk,
183
             application.name,
200 184
             status,
201
             appid,
185
             pending_appid,
202 186
             )
203 187
        l.append(t)
204 188
    return l, labels
b/snf-astakos-app/astakos/im/migrations/0043_uninitialized_projects.py
1
# encoding: utf-8
2
import datetime
3
from south.db import db
4
from south.v2 import DataMigration
5
from django.db import models
6

  
7
class Migration(DataMigration):
8

  
9
    def forwards(self, orm):
10
        objs = orm.ProjectApplication.objects
11
        apps = objs.filter(chain__chained_project=None).order_by(
12
            'chain', '-id')
13

  
14
        checked_chain = None
15
        projs = []
16
        for app in apps:
17
            chain = app.chain
18
            if chain.pk != checked_chain:
19
                checked_chain = chain.pk
20
                projs.append(orm.Project(id=chain, application=app, state=1))
21

  
22
        # use bulk_create in 1.4
23
        for proj in projs:
24
            proj.save()
25

  
26
    def backwards(self, orm):
27
        "Write your backwards methods here."
28

  
29
    models = {
30
        'auth.group': {
31
            'Meta': {'object_name': 'Group'},
32
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
33
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
34
            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
35
        },
36
        'auth.permission': {
37
            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
38
            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
39
            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
40
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
41
            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
42
        },
43
        'auth.user': {
44
            'Meta': {'object_name': 'User'},
45
            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
46
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
47
            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
48
            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
49
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
50
            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
51
            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
52
            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
53
            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
54
            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
55
            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
56
            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
57
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
58
        },
59
        'contenttypes.contenttype': {
60
            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
61
            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
62
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
63
            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
64
            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
65
        },
66
        'im.additionalmail': {
67
            'Meta': {'object_name': 'AdditionalMail'},
68
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
69
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
70
            'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
71
        },
72
        'im.approvalterms': {
73
            'Meta': {'object_name': 'ApprovalTerms'},
74
            'date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
75
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
76
            'location': ('django.db.models.fields.CharField', [], {'max_length': '255'})
77
        },
78
        'im.astakosuser': {
79
            'Meta': {'object_name': 'AstakosUser', '_ormbases': ['auth.User']},
80
            'accepted_email': ('django.db.models.fields.EmailField', [], {'default': 'None', 'max_length': '75', 'null': 'True', 'blank': 'True'}),
81
            'accepted_policy': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
82
            'activation_sent': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
83
            'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
84
            'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
85
            'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
86
            'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
87
            'date_signed_terms': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
88
            'deactivated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
89
            'deactivated_reason': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True'}),
90
            'disturbed_quota': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
91
            'email_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
92
            'has_credits': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
93
            'has_signed_terms': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
94
            'invitations': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
95
            'is_rejected': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
96
            'is_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
97
            'level': ('django.db.models.fields.IntegerField', [], {'default': '4'}),
98
            'moderated': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
99
            'moderated_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
100
            'moderated_data': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
101
            'policy': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.AstakosUserQuota']", 'symmetrical': 'False'}),
102
            'rejected_reason': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
103
            'updated': ('django.db.models.fields.DateTimeField', [], {}),
104
            'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
105
            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '255', 'unique': 'True', 'null': 'True'}),
106
            'verification_code': ('django.db.models.fields.CharField', [], {'max_length': '255', 'unique': 'True', 'null': 'True'}),
107
            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
108
        },
109
        'im.astakosuserauthprovider': {
110
            'Meta': {'unique_together': "(('identifier', 'module', 'user'),)", 'object_name': 'AstakosUserAuthProvider'},
111
            'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
112
            'affiliation': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
113
            'auth_backend': ('django.db.models.fields.CharField', [], {'default': "'astakos'", 'max_length': '255'}),
114
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
115
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
116
            'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
117
            'info_data': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
118
            'module': ('django.db.models.fields.CharField', [], {'default': "'local'", 'max_length': '255'}),
119
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_providers'", 'to': "orm['im.AstakosUser']"})
120
        },
121
        'im.astakosuserquota': {
122
            'Meta': {'unique_together': "(('resource', 'user'),)", 'object_name': 'AstakosUserQuota'},
123
            'capacity': ('snf_django.lib.db.fields.IntDecimalField', [], {'max_digits': '38', 'decimal_places': '0'}),
124
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
125
            'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"}),
126
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
127
        },
128
        'im.authproviderpolicyprofile': {
129
            'Meta': {'object_name': 'AuthProviderPolicyProfile'},
130
            'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
131
            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authpolicy_profiles'", 'symmetrical': 'False', 'to': "orm['auth.Group']"}),
132
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
133
            'is_exclusive': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
134
            'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
135
            'policy_add': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
136
            'policy_automoderate': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
137
            'policy_create': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
138
            'policy_limit': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'}),
139
            'policy_login': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
140
            'policy_remove': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
141
            'policy_required': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
142
            'policy_switch': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
143
            'priority': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
144
            'provider': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
145
            'users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authpolicy_profiles'", 'symmetrical': 'False', 'to': "orm['im.AstakosUser']"})
146
        },
147
        'im.chain': {
148
            'Meta': {'object_name': 'Chain'},
149
            'chain': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
150
        },
151
        'im.component': {
152
            'Meta': {'object_name': 'Component'},
153
            'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
154
            'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
155
            'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
156
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
157
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
158
            'url': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'})
159
        },
160
        'im.emailchange': {
161
            'Meta': {'object_name': 'EmailChange'},
162
            'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
163
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
164
            'new_email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
165
            'requested_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
166
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emailchanges'", 'unique': 'True', 'to': "orm['im.AstakosUser']"})
167
        },
168
        'im.endpoint': {
169
            'Meta': {'object_name': 'Endpoint'},
170
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
171
            'service': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'endpoints'", 'to': "orm['im.Service']"})
172
        },
173
        'im.endpointdata': {
174
            'Meta': {'unique_together': "(('endpoint', 'key'),)", 'object_name': 'EndpointData'},
175
            'endpoint': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'data'", 'to': "orm['im.Endpoint']"}),
176
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
177
            'key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
178
            'value': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
179
        },
180
        'im.invitation': {
181
            'Meta': {'object_name': 'Invitation'},
182
            'code': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
183
            'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
184
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
185
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
186
            'inviter': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'invitations_sent'", 'null': 'True', 'to': "orm['im.AstakosUser']"}),
187
            'is_consumed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
188
            'realname': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
189
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
190
        },
191
        'im.pendingthirdpartyuser': {
192
            'Meta': {'unique_together': "(('provider', 'third_party_identifier'),)", 'object_name': 'PendingThirdPartyUser'},
193
            'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
194
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
195
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
196
            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
197
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
198
            'info': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
199
            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
200
            'provider': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
201
            'third_party_identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
202
            'token': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
203
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
204
        },
205
        'im.project': {
206
            'Meta': {'object_name': 'Project'},
207
            'application': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'project'", 'unique': 'True', 'to': "orm['im.ProjectApplication']"}),
208
            'creation_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
209
            'deactivation_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
210
            'deactivation_reason': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
211
            'id': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'chained_project'", 'unique': 'True', 'primary_key': 'True', 'db_column': "'id'", 'to': "orm['im.Chain']"}),
212
            'last_approval_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
213
            'members': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.AstakosUser']", 'through': "orm['im.ProjectMembership']", 'symmetrical': 'False'}),
214
            'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'unique': 'True', 'null': 'True', 'db_index': 'True'}),
215
            'state': ('django.db.models.fields.IntegerField', [], {'default': '1', 'db_index': 'True'})
216
        },
217
        'im.projectapplication': {
218
            'Meta': {'unique_together': "(('chain', 'id'),)", 'object_name': 'ProjectApplication'},
219
            'applicant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'projects_applied'", 'to': "orm['im.AstakosUser']"}),
220
            'chain': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'chained_apps'", 'db_column': "'chain'", 'to': "orm['im.Chain']"}),
221
            'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
222
            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
223
            'end_date': ('django.db.models.fields.DateTimeField', [], {}),
224
            'homepage': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True'}),
225
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
226
            'issue_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
227
            'limit_on_members_number': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
228
            'member_join_policy': ('django.db.models.fields.IntegerField', [], {}),
229
            'member_leave_policy': ('django.db.models.fields.IntegerField', [], {}),
230
            'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
231
            'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'projects_owned'", 'to': "orm['im.AstakosUser']"}),
232
            'precursor_application': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.ProjectApplication']", 'null': 'True', 'blank': 'True'}),
233
            'resource_grants': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.ProjectResourceGrant']", 'blank': 'True'}),
234
            'response': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
235
            'response_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
236
            'start_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
237
            'state': ('django.db.models.fields.IntegerField', [], {'default': '0', 'db_index': 'True'})
238
        },
239
        'im.projectmembership': {
240
            'Meta': {'unique_together': "(('person', 'project'),)", 'object_name': 'ProjectMembership'},
241
            'acceptance_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'db_index': 'True'}),
242
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
243
            'leave_request_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
244
            'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"}),
245
            'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Project']"}),
246
            'request_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
247
            'state': ('django.db.models.fields.IntegerField', [], {'default': '0', 'db_index': 'True'})
248
        },
249
        'im.projectmembershiphistory': {
250
            'Meta': {'object_name': 'ProjectMembershipHistory'},
251
            'date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
252
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
253
            'person': ('django.db.models.fields.BigIntegerField', [], {}),
254
            'project': ('django.db.models.fields.BigIntegerField', [], {}),
255
            'reason': ('django.db.models.fields.IntegerField', [], {}),
256
            'serial': ('django.db.models.fields.BigIntegerField', [], {})
257
        },
258
        'im.projectresourcegrant': {
259
            'Meta': {'unique_together': "(('resource', 'project_application'),)", 'object_name': 'ProjectResourceGrant'},
260
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
261
            'member_capacity': ('snf_django.lib.db.fields.IntDecimalField', [], {'default': '0', 'max_digits': '38', 'decimal_places': '0'}),
262
            'project_application': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.ProjectApplication']", 'null': 'True'}),
263
            'project_capacity': ('snf_django.lib.db.fields.IntDecimalField', [], {'null': 'True', 'max_digits': '38', 'decimal_places': '0'}),
264
            'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"})
265
        },
266
        'im.resource': {
267
            'Meta': {'object_name': 'Resource'},
268
            'allow_in_projects': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
269
            'desc': ('django.db.models.fields.TextField', [], {'null': 'True'}),
270
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
271
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
272
            'service_origin': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
273
            'service_type': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
274
            'unit': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
275
            'uplimit': ('snf_django.lib.db.fields.IntDecimalField', [], {'default': '0', 'max_digits': '38', 'decimal_places': '0'})
276
        },
277
        'im.serial': {
278
            'Meta': {'object_name': 'Serial'},
279
            'serial': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
280
        },
281
        'im.service': {
282
            'Meta': {'object_name': 'Service'},
283
            'component': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Component']"}),
284
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
285
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
286
            'type': ('django.db.models.fields.CharField', [], {'max_length': '255'})
287
        },
288
        'im.sessioncatalog': {
289
            'Meta': {'object_name': 'SessionCatalog'},
290
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
291
            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
292
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sessions'", 'null': 'True', 'to': "orm['im.AstakosUser']"})
293
        },
294
        'im.usersetting': {
295
            'Meta': {'unique_together': "(('user', 'setting'),)", 'object_name': 'UserSetting'},
296
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
297
            'setting': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
298
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"}),
299
            'value': ('django.db.models.fields.IntegerField', [], {})
300
        }
301
    }
302

  
303
    complete_apps = ['im']
b/snf-astakos-app/astakos/im/migrations/0044_auto__chg_field_projectapplication_chain__chg_field_project_id.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
        # Changing field 'ProjectApplication.chain'
12
        db.alter_column('im_projectapplication', 'chain', self.gf('django.db.models.fields.related.ForeignKey')(db_column='chain', to=orm['im.Project']))
13

  
14
        # Changing field 'Project.id'
15
        db.alter_column('im_project', 'id', self.gf('django.db.models.fields.BigIntegerField')(primary_key=True, db_column='id'))
16

  
17
        # Removing index on 'Project', fields ['id']
18
        db.delete_index('im_project', ['id'])
19
    
20
    
21
    def backwards(self, orm):
22
        
23
        # Changing field 'ProjectApplication.chain'
24
        db.alter_column('im_projectapplication', 'chain', self.gf('django.db.models.fields.related.ForeignKey')(db_column='chain', to=orm['im.Chain']))
25

  
26
        # Changing field 'Project.id'
27
        db.alter_column('im_project', 'id', self.gf('django.db.models.fields.related.OneToOneField')(unique=True, primary_key=True, db_column='id', to=orm['im.Chain']))
28

  
29
        # Adding index on 'Project', fields ['id']
30
        db.create_index('im_project', ['id'])
31
    
32
    
33
    models = {
34
        'auth.group': {
35
            'Meta': {'object_name': 'Group'},
36
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
37
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
38
            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
39
        },
40
        'auth.permission': {
41
            'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
42
            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
43
            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
44
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
45
            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
46
        },
47
        'auth.user': {
48
            'Meta': {'object_name': 'User'},
49
            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
50
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
51
            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
52
            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
53
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
54
            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
55
            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
56
            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
57
            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
58
            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
59
            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
60
            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
61
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
62
        },
63
        'contenttypes.contenttype': {
64
            'Meta': {'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
65
            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
66
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
67
            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
68
            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
69
        },
70
        'im.additionalmail': {
71
            'Meta': {'object_name': 'AdditionalMail'},
72
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
73
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
74
            'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
75
        },
76
        'im.approvalterms': {
77
            'Meta': {'object_name': 'ApprovalTerms'},
78
            'date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'db_index': 'True', 'blank': 'True'}),
79
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
80
            'location': ('django.db.models.fields.CharField', [], {'max_length': '255'})
81
        },
82
        'im.astakosuser': {
83
            'Meta': {'object_name': 'AstakosUser', '_ormbases': ['auth.User']},
84
            'accepted_email': ('django.db.models.fields.EmailField', [], {'default': 'None', 'max_length': '75', 'null': 'True', 'blank': 'True'}),
85
            'accepted_policy': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
86
            'activation_sent': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
87
            'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
88
            'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
89
            'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
90
            'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
91
            'date_signed_terms': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
92
            'deactivated_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
93
            'deactivated_reason': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True'}),
94
            'disturbed_quota': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True', 'blank': 'True'}),
95
            'email_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
96
            'has_credits': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
97
            'has_signed_terms': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
98
            'invitations': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
99
            'is_rejected': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
100
            'is_verified': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
101
            'level': ('django.db.models.fields.IntegerField', [], {'default': '4'}),
102
            'moderated': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
103
            'moderated_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
104
            'moderated_data': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
105
            'policy': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.AstakosUserQuota']", 'symmetrical': 'False'}),
106
            'rejected_reason': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
107
            'updated': ('django.db.models.fields.DateTimeField', [], {}),
108
            'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}),
109
            'uuid': ('django.db.models.fields.CharField', [], {'max_length': '255', 'unique': 'True', 'null': 'True'}),
110
            'verification_code': ('django.db.models.fields.CharField', [], {'max_length': '255', 'unique': 'True', 'null': 'True'}),
111
            'verified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
112
        },
113
        'im.astakosuserauthprovider': {
114
            'Meta': {'unique_together': "(('identifier', 'module', 'user'),)", 'object_name': 'AstakosUserAuthProvider'},
115
            'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
116
            'affiliation': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'null': 'True', 'blank': 'True'}),
117
            'auth_backend': ('django.db.models.fields.CharField', [], {'default': "'astakos'", 'max_length': '255'}),
118
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
119
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
120
            'identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
121
            'info_data': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
122
            'module': ('django.db.models.fields.CharField', [], {'default': "'local'", 'max_length': '255'}),
123
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_providers'", 'to': "orm['im.AstakosUser']"})
124
        },
125
        'im.astakosuserquota': {
126
            'Meta': {'unique_together': "(('resource', 'user'),)", 'object_name': 'AstakosUserQuota'},
127
            'capacity': ('snf_django.lib.db.fields.IntDecimalField', [], {'max_digits': '38', 'decimal_places': '0'}),
128
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
129
            'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"}),
130
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"})
131
        },
132
        'im.authproviderpolicyprofile': {
133
            'Meta': {'object_name': 'AuthProviderPolicyProfile'},
134
            'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
135
            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authpolicy_profiles'", 'symmetrical': 'False', 'to': "orm['auth.Group']"}),
136
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
137
            'is_exclusive': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
138
            'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
139
            'policy_add': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
140
            'policy_automoderate': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
141
            'policy_create': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
142
            'policy_limit': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'null': 'True'}),
143
            'policy_login': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
144
            'policy_remove': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
145
            'policy_required': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
146
            'policy_switch': ('django.db.models.fields.NullBooleanField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
147
            'priority': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
148
            'provider': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
149
            'users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authpolicy_profiles'", 'symmetrical': 'False', 'to': "orm['im.AstakosUser']"})
150
        },
151
        'im.chain': {
152
            'Meta': {'object_name': 'Chain'},
153
            'chain': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
154
        },
155
        'im.component': {
156
            'Meta': {'object_name': 'Component'},
157
            'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
158
            'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
159
            'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
160
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
161
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255', 'db_index': 'True'}),
162
            'url': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True'})
163
        },
164
        'im.emailchange': {
165
            'Meta': {'object_name': 'EmailChange'},
166
            'activation_key': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
167
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
168
            'new_email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
169
            'requested_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
170
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'emailchanges'", 'unique': 'True', 'to': "orm['im.AstakosUser']"})
171
        },
172
        'im.endpoint': {
173
            'Meta': {'object_name': 'Endpoint'},
174
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
175
            'service': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'endpoints'", 'to': "orm['im.Service']"})
176
        },
177
        'im.endpointdata': {
178
            'Meta': {'unique_together': "(('endpoint', 'key'),)", 'object_name': 'EndpointData'},
179
            'endpoint': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'data'", 'to': "orm['im.Endpoint']"}),
180
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
181
            'key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
182
            'value': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
183
        },
184
        'im.invitation': {
185
            'Meta': {'object_name': 'Invitation'},
186
            'code': ('django.db.models.fields.BigIntegerField', [], {'db_index': 'True'}),
187
            'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
188
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
189
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
190
            'inviter': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'invitations_sent'", 'null': 'True', 'to': "orm['im.AstakosUser']"}),
191
            'is_consumed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
192
            'realname': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
193
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
194
        },
195
        'im.pendingthirdpartyuser': {
196
            'Meta': {'unique_together': "(('provider', 'third_party_identifier'),)", 'object_name': 'PendingThirdPartyUser'},
197
            'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
198
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
199
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
200
            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
201
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
202
            'info': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
203
            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
204
            'provider': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
205
            'third_party_identifier': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
206
            'token': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
207
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
208
        },
209
        'im.project': {
210
            'Meta': {'object_name': 'Project'},
211
            'application': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'project'", 'unique': 'True', 'to': "orm['im.ProjectApplication']"}),
212
            'creation_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
213
            'deactivation_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
214
            'deactivation_reason': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
215
            'id': ('django.db.models.fields.BigIntegerField', [], {'primary_key': 'True', 'db_column': "'id'"}),
216
            'last_approval_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
217
            'members': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['im.AstakosUser']", 'through': "orm['im.ProjectMembership']", 'symmetrical': 'False'}),
218
            'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'unique': 'True', 'null': 'True', 'db_index': 'True'}),
219
            'state': ('django.db.models.fields.IntegerField', [], {'default': '1', 'db_index': 'True'})
220
        },
221
        'im.projectapplication': {
222
            'Meta': {'unique_together': "(('chain', 'id'),)", 'object_name': 'ProjectApplication'},
223
            'applicant': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'projects_applied'", 'to': "orm['im.AstakosUser']"}),
224
            'chain': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'chained_apps'", 'db_column': "'chain'", 'to': "orm['im.Project']"}),
225
            'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
226
            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
227
            'end_date': ('django.db.models.fields.DateTimeField', [], {}),
228
            'homepage': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True'}),
229
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
230
            'issue_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
231
            'limit_on_members_number': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
232
            'member_join_policy': ('django.db.models.fields.IntegerField', [], {}),
233
            'member_leave_policy': ('django.db.models.fields.IntegerField', [], {}),
234
            'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
235
            'owner': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'projects_owned'", 'to': "orm['im.AstakosUser']"}),
236
            'precursor_application': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.ProjectApplication']", 'null': 'True', 'blank': 'True'}),
237
            'resource_grants': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['im.Resource']", 'null': 'True', 'through': "orm['im.ProjectResourceGrant']", 'blank': 'True'}),
238
            'response': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
239
            'response_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
240
            'start_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
241
            'state': ('django.db.models.fields.IntegerField', [], {'default': '0', 'db_index': 'True'})
242
        },
243
        'im.projectmembership': {
244
            'Meta': {'unique_together': "(('person', 'project'),)", 'object_name': 'ProjectMembership'},
245
            'acceptance_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'db_index': 'True'}),
246
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
247
            'leave_request_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
248
            'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"}),
249
            'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Project']"}),
250
            'request_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
251
            'state': ('django.db.models.fields.IntegerField', [], {'default': '0', 'db_index': 'True'})
252
        },
253
        'im.projectmembershiphistory': {
254
            'Meta': {'object_name': 'ProjectMembershipHistory'},
255
            'date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
256
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
257
            'person': ('django.db.models.fields.BigIntegerField', [], {}),
258
            'project': ('django.db.models.fields.BigIntegerField', [], {}),
259
            'reason': ('django.db.models.fields.IntegerField', [], {}),
260
            'serial': ('django.db.models.fields.BigIntegerField', [], {})
261
        },
262
        'im.projectresourcegrant': {
263
            'Meta': {'unique_together': "(('resource', 'project_application'),)", 'object_name': 'ProjectResourceGrant'},
264
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
265
            'member_capacity': ('snf_django.lib.db.fields.IntDecimalField', [], {'default': '0', 'max_digits': '38', 'decimal_places': '0'}),
266
            'project_application': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.ProjectApplication']", 'null': 'True'}),
267
            'project_capacity': ('snf_django.lib.db.fields.IntDecimalField', [], {'null': 'True', 'max_digits': '38', 'decimal_places': '0'}),
268
            'resource': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Resource']"})
269
        },
270
        'im.resource': {
271
            'Meta': {'object_name': 'Resource'},
272
            'allow_in_projects': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
273
            'desc': ('django.db.models.fields.TextField', [], {'null': 'True'}),
274
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
275
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
276
            'service_origin': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
277
            'service_type': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
278
            'unit': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
279
            'uplimit': ('snf_django.lib.db.fields.IntDecimalField', [], {'default': '0', 'max_digits': '38', 'decimal_places': '0'})
280
        },
281
        'im.serial': {
282
            'Meta': {'object_name': 'Serial'},
283
            'serial': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
284
        },
285
        'im.service': {
286
            'Meta': {'object_name': 'Service'},
287
            'component': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.Component']"}),
288
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
289
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
290
            'type': ('django.db.models.fields.CharField', [], {'max_length': '255'})
291
        },
292
        'im.sessioncatalog': {
293
            'Meta': {'object_name': 'SessionCatalog'},
294
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
295
            'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
296
            'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sessions'", 'null': 'True', 'to': "orm['im.AstakosUser']"})
297
        },
298
        'im.usersetting': {
299
            'Meta': {'unique_together': "(('user', 'setting'),)", 'object_name': 'UserSetting'},
300
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
301
            'setting': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
302
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['im.AstakosUser']"}),
303
            'value': ('django.db.models.fields.IntegerField', [], {})
304
        }
305
    }
306
    
307
    complete_apps = ['im']
b/snf-astakos-app/astakos/im/models.py
1280 1280
### PROJECTS ###
1281 1281
################
1282 1282

  
1283
class ChainManager(ForUpdateManager):
1284

  
1285
    def search_by_name(self, *search_strings):
1286
        projects = Project.objects.search_by_name(*search_strings)
1287
        chains = [p.id for p in projects]
1288
        apps = ProjectApplication.objects.search_by_name(*search_strings)
1289
        apps = (app for app in apps if app.is_latest())
1290
        app_chains = [app.chain for app in apps if app.chain not in chains]
1291
        return chains + app_chains
1292

  
1293
    def all_full_state(self):
1294
        chains = self.all()
1295
        cids = [c.chain for c in chains]
1296
        projects = Project.objects.select_related('application').in_bulk(cids)
1297

  
1298
        objs = Chain.objects.annotate(latest=Max('chained_apps__id'))
1299
        chain_latest = dict(objs.values_list('chain', 'latest'))
1300

  
1301
        objs = ProjectApplication.objects.select_related('applicant')
1302
        apps = objs.in_bulk(chain_latest.values())
1303

  
1304
        d = {}
1305
        for chain in chains:
1306
            pk = chain.pk
1307
            project = projects.get(pk, None)
1308
            app = apps[chain_latest[pk]]
1309
            d[chain.pk] = chain.get_state(project, app)
1310

  
1311
        return d
1312

  
1313
    def of_project(self, project):
1314
        if project is None:
1315
            return None
1316
        try:
1317
            return self.get(chain=project.id)
1318
        except Chain.DoesNotExist:
1319
            raise AssertionError('project with no chain')
1320

  
1321

  
1322 1283
class Chain(models.Model):
1323 1284
    chain = models.AutoField(primary_key=True)
1285
    objects = ForUpdateManager()
1324 1286

  
1325 1287
    def __str__(self):
1326 1288
        return "%s" % (self.chain,)
1327 1289

  
1328
    objects = ChainManager()
1329

  
1330
    PENDING = 0
1331
    DENIED = 3
1332
    DISMISSED = 4
1333
    CANCELLED = 5
1334

  
1335
    APPROVED = 10
1336
    APPROVED_PENDING = 11
1337
    SUSPENDED = 12
1338
    SUSPENDED_PENDING = 13
1339
    TERMINATED = 14
1340
    TERMINATED_PENDING = 15
1341

  
1342
    PENDING_STATES = [PENDING,
1343
                      APPROVED_PENDING,
1344
                      SUSPENDED_PENDING,
1345
                      TERMINATED_PENDING,
1346
                      ]
1347

  
1348
    MODIFICATION_STATES = [APPROVED_PENDING,
1349
                           SUSPENDED_PENDING,
1350
                           TERMINATED_PENDING,
1351
                           ]
1352

  
1353
    RELEVANT_STATES = [PENDING,
1354
                       DENIED,
1355
                       APPROVED,
1356
                       APPROVED_PENDING,
1357
                       SUSPENDED,
1358
                       SUSPENDED_PENDING,
1359
                       TERMINATED_PENDING,
1360
                       ]
1361

  
1362
    SKIP_STATES = [DISMISSED,
1363
                   CANCELLED,
1364
                   TERMINATED]
1365

  
1366
    STATE_DISPLAY = {
1367
        PENDING:             _("Pending"),
1368
        DENIED:              _("Denied"),
1369
        DISMISSED:           _("Dismissed"),
1370
        CANCELLED:           _("Cancelled"),
1371
        APPROVED:            _("Active"),
1372
        APPROVED_PENDING:    _("Active - Pending"),
1373
        SUSPENDED:           _("Suspended"),
1374
        SUSPENDED_PENDING:   _("Suspended - Pending"),
1375
        TERMINATED:          _("Terminated"),
1376
        TERMINATED_PENDING:  _("Terminated - Pending"),
1377
    }
1378

  
1379
    @classmethod
1380
    def _chain_state(cls, project_state, app_state):
1381
        s = CHAIN_STATE.get((project_state, app_state), None)
1382
        if s is None:
1383
            raise AssertionError('inconsistent chain state')
1384
        return s
1385

  
1386
    @classmethod
1387
    def chain_state(cls, project, app):
1388
        p_state = project.state if project else None
1389
        return cls._chain_state(p_state, app.state)
1390

  
1391
    @classmethod
1392
    def state_display(cls, s):
1393
        if s is None:
1394
            return _("Unknown")
1395
        return cls.STATE_DISPLAY.get(s, _("Inconsistent"))
1396

  
1397
    def last_application(self):
1398
        return self.chained_apps.order_by('-id')[0]
1399

  
1400
    def get_project(self):
1401
        try:
1402
            return self.chained_project
1403
        except Project.DoesNotExist:
1404
            return None
1405

  
1406
    def get_elements(self):
1407
        project = self.get_project()
1408
        app = self.last_application()
1409
        return project, app
1410

  
1411
    def get_state(self, project, app):
1412
        s = self.chain_state(project, app)
1413
        return s, project, app
1414

  
1415
    def full_state(self):
1416
        project, app = self.get_elements()
1417
        return self.get_state(project, app)
1418

  
1419 1290

  
1420 1291
def new_chain():
1421 1292
    c = Chain.objects.create()
......
1482 1353
        AstakosUser,
1483 1354
        related_name='projects_owned',
1484 1355
        db_index=True)
1485
    chain = models.ForeignKey(Chain,
1356
    chain = models.ForeignKey('Project',
1486 1357
                              related_name='chained_apps',
1487 1358
                              db_column='chain')
1488 1359
    precursor_application = models.ForeignKey('ProjectApplication',
......
1625 1496
        except Project.DoesNotExist:
1626 1497
            return False
1627 1498

  
1628
    def get_project(self):
1629
        try:
1630
            return Project.objects.get(id=self.chain)
1631
        except Project.DoesNotExist:
1632
            return None
1633

  
1634
    def project_exists(self):
1635
        return self.get_project() is not None
1636

  
1637 1499
    def can_cancel(self):
1638 1500
        return self.state == self.PENDING
1639 1501

  
......
1687 1549
        self.response = reason
1688 1550
        self.save()
1689 1551

  
1690
        project = self.get_project()
1691
        if project is None:
1692
            project = Project(id=self.chain)
1693

  
1694
        project.name = self.name
1695
        project.application = self
1696
        project.last_approval_date = now
1697
        project.save()
1698
        if project.is_deactivated():
1699
            project.resume()
1700
        return project
1701

  
1702 1552
    @property
1703 1553
    def member_join_policy_display(self):
1704 1554
        policy = self.member_join_policy
......
1765 1615
                return '0'
1766 1616

  
1767 1617

  
1768
class ProjectManager(ForUpdateManager):
1618
def _distinct(f, l):
1619
    d = {}
1620
    last = None
1621
    for x in l:
1622
        group = f(x)
1623
        if group == last:
1624
            continue
1625
        last = group
1626
        d[group] = x
1627
    return d
1769 1628

  
1770
    def terminated_projects(self):
1771
        q = self.model.Q_TERMINATED
1772
        return self.filter(q)
1773 1629

  
1774
    def not_terminated_projects(self):
1775
        q = ~self.model.Q_TERMINATED
1776
        return self.filter(q)
1630
def invert_dict(d):
1631
    return dict((v, k) for k, v in d.iteritems())
1777 1632

  
1778
    def deactivated_projects(self):
1779
        q = self.model.Q_DEACTIVATED
1780
        return self.filter(q)
1633

  
1634
class ProjectManager(ForUpdateManager):
1635

  
1636
    def all_with_pending(self, flt=None):
1637
        flt = Q() if flt is None else flt
1638
        projects = list(self.select_related(
1639
            'application', 'application__owner').filter(flt))
1640

  
1641
        objs = ProjectApplication.objects.select_related('owner')
1642
        apps = objs.filter(state=ProjectApplication.PENDING,
1643
                           chain__in=projects).order_by('chain', '-id')
1644
        app_d = _distinct(lambda app: app.chain_id, apps)
1645
        return [(project, app_d.get(project.pk)) for project in projects]
1781 1646

  
1782 1647
    def expired_projects(self):
1783
        q = (~Q(state=Project.TERMINATED) &
1648
        model = self.model
1649
        q = ((model.o_state_q(model.O_ACTIVE) |
1650
              model.o_state_q(model.O_SUSPENDED)) &
1784 1651
             Q(application__end_date__lt=datetime.now()))
1785 1652
        return self.filter(q)
1786 1653

  
1787
    def search_by_name(self, *search_strings):
1788
        q = Q()
1789
        for s in search_strings:
1790
            q = q | Q(name__icontains=s)
1791
        return self.filter(q)
1792

  
1793 1654

  
1794 1655
class Project(models.Model):
1795 1656

  
1796
    id = models.OneToOneField(Chain,
1797
                              related_name='chained_project',
1798
                              db_column='id',
1799
                              primary_key=True)
1657
    id = models.BigIntegerField(db_column='id', primary_key=True)
1800 1658

  
1801 1659
    application = models.OneToOneField(
1802 1660
        ProjectApplication,
......
1817 1675
        db_index=True,
1818 1676
        unique=True)
1819 1677

  
1820
    APPROVED = 1
1678
    NORMAL = 1
1821 1679
    SUSPENDED = 10
1822 1680
    TERMINATED = 100
1823 1681

  
1824
    state = models.IntegerField(default=APPROVED,
1682
    state = models.IntegerField(default=NORMAL,
1825 1683
                                db_index=True)
1826 1684

  
1827 1685
    objects = ProjectManager()
1828 1686

  
1829
    # Compiled queries
1830
    Q_TERMINATED = Q(state=TERMINATED)
1831
    Q_SUSPENDED = Q(state=SUSPENDED)
1832
    Q_DEACTIVATED = Q_TERMINATED | Q_SUSPENDED
1833

  
1834 1687
    def __str__(self):
1835 1688
        return uenc(_("<project %s '%s'>") %
1836 1689
                    (self.id, udec(self.application.name)))
......
1840 1693
    def __unicode__(self):
1841 1694
        return _("<project %s '%s'>") % (self.id, self.application.name)
1842 1695

  
1843
    STATE_DISPLAY = {
1844
        APPROVED:   'Active',
1845
        SUSPENDED:  'Suspended',
1846
        TERMINATED: 'Terminated'
1696
    O_PENDING = 0
1697
    O_ACTIVE = 1
1698
    O_DENIED = 3
1699
    O_DISMISSED = 4
1700
    O_CANCELLED = 5
1701
    O_SUSPENDED = 10
1702
    O_TERMINATED = 100
1703

  
1704
    O_STATE_DISPLAY = {
1705
        O_PENDING:    _("Pending"),
1706
        O_ACTIVE:     _("Active"),
1707
        O_DENIED:     _("Denied"),
1708
        O_DISMISSED:  _("Dismissed"),
1709
        O_CANCELLED:  _("Cancelled"),
1710
        O_SUSPENDED:  _("Suspended"),
1711
        O_TERMINATED: _("Terminated"),
1847 1712
    }
1848 1713

  
1714
    OVERALL_STATE = {
1715
        (NORMAL, ProjectApplication.PENDING):      O_PENDING,
1716
        (NORMAL, ProjectApplication.APPROVED):     O_ACTIVE,
1717
        (NORMAL, ProjectApplication.DENIED):       O_DENIED,
1718
        (NORMAL, ProjectApplication.DISMISSED):    O_DISMISSED,
1719
        (NORMAL, ProjectApplication.CANCELLED):    O_CANCELLED,
1720
        (SUSPENDED, ProjectApplication.APPROVED):  O_SUSPENDED,
1721
        (TERMINATED, ProjectApplication.APPROVED): O_TERMINATED,
1722
    }
1723

  
1724
    OVERALL_STATE_INV = invert_dict(OVERALL_STATE)
1725

  
1726
    @classmethod
1727
    def o_state_q(cls, o_state):
1728
        p_state, a_state = cls.OVERALL_STATE_INV[o_state]
1729
        return Q(state=p_state, application__state=a_state)
1730

  
1731
    INITIALIZED_STATES = [O_ACTIVE,
1732
                          O_SUSPENDED,
1733
                          O_TERMINATED,
1734
                          ]
1735

  
1736
    RELEVANT_STATES = [O_PENDING,
1737
                       O_DENIED,
1738
                       O_ACTIVE,
1739
                       O_SUSPENDED,
1740
                       O_TERMINATED,
1741
                       ]
1742

  
1743
    SKIP_STATES = [O_DISMISSED,
1744
                   O_CANCELLED,
1745
                   O_TERMINATED,
1746
                   ]
1747

  
1748
    @classmethod
1749
    def _overall_state(cls, project_state, app_state):
1750
        return cls.OVERALL_STATE.get((project_state, app_state), None)
1751

  
1752
    def overall_state(self):
1753
        return self._overall_state(self.state, self.application.state)
1754

  
1755
    def last_pending_application(self):
1756
        apps = self.chained_apps.filter(
1757
            state=ProjectApplication.PENDING).order_by('-id')
1758
        if apps:
1759
            return apps[0]
1760
        return None
1761

  
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff