Revision b10ceccd

b/snf-astakos-app/astakos/im/functions.py
583 583
        raise ProjectConflict(m)
584 584

  
585 585

  
586
def can_join_request(project, user):
586
Nothing = type('Nothing', (), {})
587

  
588

  
589
def can_join_request(project, user, membership=Nothing):
587 590
    try:
588 591
        join_project_checks(project)
589 592
    except ProjectError:
590 593
        return False
591 594

  
592
    m = user.get_membership(project)
595
    m = (membership if membership is not Nothing
596
         else user.get_membership(project))
593 597
    if not m:
594 598
        return True
595 599
    return m.check_action("join")
b/snf-astakos-app/astakos/im/models.py
1283 1283

  
1284 1284

  
1285 1285
class ProjectApplicationManager(ForUpdateManager):
1286
    pass
1286

  
1287
    def pending_per_project(self, projects):
1288
        apps = self.filter(state=self.model.PENDING,
1289
                           chain__in=projects).order_by('chain', '-id')
1290
        checked_chain = None
1291
        projs = {}
1292
        for app in apps:
1293
            chain = app.chain_id
1294
            if chain != checked_chain:
1295
                checked_chain = chain
1296
                projs[chain] = app
1297
        return projs
1287 1298

  
1288 1299

  
1289 1300
class ProjectApplication(models.Model):
......
1666 1677
            return None
1667 1678
        return last_pending
1668 1679

  
1669
    def has_pending_modifications(self):
1670
        last_pending = self.last_pending_modification()
1671
        return last_pending is not None
1672

  
1673 1680
    def state_display(self):
1674 1681
        return self.O_STATE_DISPLAY.get(self.overall_state(), _('Unknown'))
1675 1682

  
......
1806 1813
    def associated(self):
1807 1814
        return self.filter(state__in=ProjectMembership.ASSOCIATED_STATES)
1808 1815

  
1816
    def any_accepted_per_project(self, projects):
1817
        ms = self.any_accepted().filter(project__in=projects)
1818
        return _partition_by(lambda m: m.project_id, ms)
1819

  
1820
    def requested_per_project(self, projects):
1821
        ms = self.requested().filter(project__in=projects)
1822
        return _partition_by(lambda m: m.project_id, ms)
1823

  
1824
    def one_per_project(self):
1825
        ms = self.all().select_related(
1826
            'project', 'project__application',
1827
            'project__application__owner', 'project_application__applicant',
1828
            'person')
1829
        m_per_p = {}
1830
        for m in ms:
1831
            m_per_p[m.project_id] = m
1832
        return m_per_p
1833

  
1809 1834

  
1810 1835
class ProjectMembership(models.Model):
1811 1836

  
b/snf-astakos-app/astakos/im/tables.py
182 182
    user = table.user
183 183
    url, action, confirm, prompt = '', '', True, ''
184 184

  
185
    membership = user.get_membership(project)
185
    membership = table.memberships.get(project.id)
186 186
    if membership is not None:
187 187
        allowed = membership_allowed_actions(membership, user)
188 188
        if 'leave' in allowed:
......
198 198
            confirm = True
199 199
            prompt = _('Are you sure you want to cancel the join request?')
200 200

  
201
    if can_join_request(project, user):
201
    if can_join_request(project, user, membership):
202 202
        url = reverse('astakos.im.views.project_join', args=(project.id,))
203 203
        action = _('Join')
204 204
        confirm = True
......
225 225

  
226 226

  
227 227
def project_name_append(project, column):
228
    if project.has_pending_modifications():
228
    pending_apps = column.table.pending_apps
229
    app = pending_apps.get(project.id)
230
    if app and app.id != project.application_id:
229 231
        return mark_safe("<br /><i class='tiny'>%s</i>" %
230 232
                         _('modifications pending'))
231 233
    return u''
......
233 235

  
234 236
# Table classes
235 237
class UserProjectsTable(UserTable):
238

  
239
    def __init__(self, *args, **kwargs):
240
        self.pending_apps = kwargs.pop('pending_apps')
241
        self.memberships = kwargs.pop('memberships')
242
        self.accepted = kwargs.pop('accepted')
243
        self.requested = kwargs.pop('requested')
244
        super(UserProjectsTable, self).__init__(*args, **kwargs)
245

  
236 246
    caption = _('My projects')
237 247

  
238 248
    name = LinkColumn('astakos.im.views.project_detail',
......
249 259
    end_date = tables.DateColumn(verbose_name=_('Expiration'),
250 260
                                 format=DEFAULT_DATE_FORMAT,
251 261
                                 accessor='application.end_date')
252
    members_count = tables.Column(verbose_name=_("Members"), default=0,
253
                                  orderable=False)
262
    members_count_f = tables.Column(verbose_name=_("Members"),
263
                                    empty_values=(),
264
                                    orderable=False)
254 265
    membership_status = tables.Column(verbose_name=_("Status"),
255 266
                                      empty_values=(),
256 267
                                      orderable=False)
......
262 273
        if self.user.owns_project(record) or self.user.is_project_admin():
263 274
            return record.state_display()
264 275
        else:
265
            return self.user.membership_display(record)
276
            m = self.memberships.get(record.id)
277
            if m:
278
                return m.user_friendly_state_display()
279
            return _('Not a member')
266 280

  
267
    def render_members_count(self, record, *args, **kwargs):
281
    def render_members_count_f(self, record, *args, **kwargs):
268 282
        append = ""
269 283
        project = record
270 284
        if project is None:
271 285
            append = mark_safe("<i class='tiny'>%s</i>" % (_('pending'),))
272 286

  
273
        c = project.count_pending_memberships()
287
        c = len(self.requested.get(project.id, []))
274 288
        if c > 0:
275 289
            pending_members_url = reverse(
276 290
                'project_pending_members',
......
288 302
            append = mark_safe(pending_members)
289 303
        members_url = reverse('project_approved_members',
290 304
                              kwargs={'chain_id': record.id})
291
        members_count = record.members_count()
305
        members_count = len(self.accepted.get(project.id, []))
292 306
        if self.user.owns_project(record) or self.user.is_project_admin():
293 307
            members_count = '<a href="%s">%d</a>' % (members_url,
294 308
                                                     members_count)
......
296 310

  
297 311
    class Meta:
298 312
        sequence = ('name', 'membership_status', 'issue_date', 'end_date',
299
                    'members_count', 'project_action')
313
                    'members_count_f', 'project_action')
300 314
        attrs = {'id': 'projects-list', 'class': 'my-projects alt-style'}
301 315
        template = "im/table_render.html"
302 316
        empty_text = _('No projects')
b/snf-astakos-app/astakos/im/views/projects.py
138 138
        messages.error(request, e)
139 139

  
140 140

  
141
def get_user_projects_table(projects, user, prefix):
142
    apps = ProjectApplication.objects.pending_per_project(projects)
143
    memberships = user.projectmembership_set.one_per_project()
144
    objs = ProjectMembership.objects
145
    accepted_ms = objs.any_accepted_per_project(projects)
146
    requested_ms = objs.requested_per_project(projects)
147
    return tables.UserProjectsTable(projects, user=user,
148
                                    prefix=prefix,
149
                                    pending_apps=apps,
150
                                    memberships=memberships,
151
                                    accepted=accepted_ms,
152
                                    requested=requested_ms)
153

  
154

  
141 155
@require_http_methods(["GET"])
142 156
@cookie_fix
143 157
@valid_astakos_user_required
144 158
def project_list(request):
145
    projects = Project.objects.user_accessible_projects(
146
        request.user).select_related()
147
    table = tables.UserProjectsTable(projects, user=request.user,
148
                                     prefix="my_projects_")
159
    projects = Project.objects.user_accessible_projects(request.user)
160
    table = get_user_projects_table(projects, user=request.user,
161
                                    prefix="my_projects_")
149 162
    RequestConfig(request,
150 163
                  paginate={"per_page": settings.PAGINATE_BY}).configure(table)
151 164

  
......
424 437

  
425 438
        projects = Project.objects.search_by_name(q)
426 439
        projects = projects.filter(Project.o_state_q(Project.O_ACTIVE))
427
        projects = projects.exclude(id__in=accepted)
440
        projects = projects.exclude(id__in=accepted).select_related(
441
            'application', 'application__owner', 'application__applicant')
428 442

  
429
    table = tables.UserProjectsTable(projects, user=request.user,
430
                                     prefix="my_projects_")
443
    table = get_user_projects_table(projects, user=request.user,
444
                                    prefix="my_projects_")
431 445
    if request.method == "POST":
432 446
        table.caption = _('SEARCH RESULTS')
433 447
    else:

Also available in: Unified diff