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