Switch to unified view

a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
...
...
292
            project = Project.query.get(_id=p, deleted=False)
292
            project = Project.query.get(_id=p, deleted=False)
293
            if project and self._id in [role.user_id for role in project.roles] and not project.shortname.startswith('u/'):
293
            if project and self._id in [role.user_id for role in project.roles] and not project.shortname.startswith('u/'):
294
                yield project
294
                yield project
295
295
296
    def role_iter(self):
296
    def role_iter(self):
297
        anon_role = ProjectRole.query.get(name='*anonymous')
297
        anon_role = ProjectRole.anonymous()
298
        auth_role = ProjectRole.query.get(name='*authenticated')
298
        auth_role = ProjectRole.authenticated()
299
        if anon_role:
299
        if anon_role:
300
            yield anon_role
300
            yield anon_role
301
        if self._id and auth_role:
301
        if self._id and auth_role:
302
            yield auth_role
302
            yield auth_role
303
        if self._id:
303
        if self._id:
304
            pr = self.project_role()
304
            pr = self.project_role()
305
            for role in pr.role_iter():
305
            for role in pr.role_iter():
306
                yield role
306
                yield role
307
307
308
    def project_role(self, project=None):
308
    def project_role(self, project=None):
309
        if project is None: project = c.project
309
        if project is None: project = c.project.root_project
310
        with h.push_config(c, project=project, user=self):
310
        with h.push_config(c, project=project, user=self):
311
            if self._id is None:
311
            if self._id is None:
312
                return ProjectRole.query.get(name='*anonymous')
312
                return ProjectRole.anonymous(project)
313
            pr = ProjectRole.query.get(user_id=self._id)
314
            if pr: return pr
315
            try:
316
                obj = ProjectRole(user_id=self._id)
317
                session(obj).insert_now(obj, state(obj))
318
                self.projects.append(c.project._id)
319
                return obj
320
            except pymongo.errors.DuplicateKeyError:
321
                session(obj).expunge(obj)
322
                return ProjectRole.query.get(user_id=self._id)
313
            return ProjectRole.upsert(user_id=self._id, project_id=project._id)
323
314
324
    def set_password(self, new_password):
315
    def set_password(self, new_password):
325
        return plugin.AuthenticationProvider.get(request).set_password(
316
        return plugin.AuthenticationProvider.get(request).set_password(
326
            self, self.password, new_password)
317
            self, self.password, new_password)
327
318
...
...
331
322
332
class ProjectRole(MappedClass):
323
class ProjectRole(MappedClass):
333
    class __mongometa__:
324
    class __mongometa__:
334
        session = project_orm_session
325
        session = project_orm_session
335
        name='user'
326
        name='user'
336
        unique_indexes = [ ('name', 'user_id') ]
327
        unique_indexes = [ ('user_id', 'project_id', 'name') ]
337
    
328
    
338
    _id = FieldProperty(S.ObjectId)
329
    _id = FieldProperty(S.ObjectId)
330
    user_id = FieldProperty(S.ObjectId, if_missing=None) # if role is a user
331
    project_id = FieldProperty(S.ObjectId, if_missing=lambda:c.project._id)
339
    name = FieldProperty(str)
332
    name = FieldProperty(str)
340
    user_id = FieldProperty(S.ObjectId, if_missing=None) # if role is a user
341
    roles = FieldProperty([S.ObjectId])
333
    roles = FieldProperty([S.ObjectId])
334
335
    def __init__(self, **kw):
336
        assert 'project_id' in kw, 'Project roles must specify a project id'
337
        super(ProjectRole, self).__init__(**kw)
342
338
343
    def display(self):
339
    def display(self):
344
        if self.name: return self.name
340
        if self.name: return self.name
345
        if self.user_id:
341
        if self.user_id:
346
            u = self.user
342
            u = self.user
...
...
349
            else: uname = u._id
345
            else: uname = u._id
350
            return '*user-%s' % uname
346
            return '*user-%s' % uname
351
        return '**unknown name role: %s' % self._id # pragma no cover
347
        return '**unknown name role: %s' % self._id # pragma no cover
352
348
353
    @classmethod
349
    @classmethod
350
    def by_user(cls, user=None, project=None):
351
        if user is None: user = c.user
352
        if project is None: project = c.project.root_project
353
        return cls.query.get(user_id=user._id, project_id=project._id)
354
355
    @classmethod
356
    def by_name(cls, name, project=None):
357
        if project is None: project = c.project.root_project
358
        return cls.query.get(name=name, project_id=project._id)
359
360
    @classmethod
361
    def anonymous(cls, project=None):
362
        if project is None: project = c.project.root_project
363
        return cls.by_name('*anonymous', project)
364
365
    @classmethod
366
    def authenticated(cls, project=None):
367
        if project is None: project = c.project.root_project
368
        return cls.by_name('*authenticated', project)
369
370
    @classmethod
354
    def upsert(cls, **kw):
371
    def upsert(cls, **kw):
372
        obj = cls.query.get(**kw)
373
        if obj is not None: return obj
355
        try:
374
        try:
356
            obj = cls(**kw)
375
            obj = cls(**kw)
357
            session(obj).insert_now(obj, state(obj))
376
            session(obj).insert_now(obj, state(obj))
358
        except pymongo.errors.DuplicateKeyError:
377
        except pymongo.errors.DuplicateKeyError:
359
            session(obj).expunge(obj)
378
            session(obj).expunge(obj)
...
...
368
            return True
387
            return True
369
        return False # pragma no cover
388
        return False # pragma no cover
370
389
371
    @property
390
    @property
372
    def user(self):
391
    def user(self):
392
        if self.user_id is None: return None
373
        return User.query.get(_id=self.user_id)
393
        return User.query.get(_id=self.user_id)
374
394
395
    @classmethod
396
    def roles_reachable_from(cls, *roots):
397
        to_visit = list(roots)
398
        visited = set()
399
        while to_visit:
400
            pr = to_visit.pop(0)
401
            if pr in visited: continue
402
            visited.add(pr)
403
            yield pr
404
            to_visit += cls.query.find(dict(_id={'$in':pr.roles})).all()
405
406
    @classmethod
407
    def roles_that_reach(cls, *roots):
408
        to_visit = list(roots)
409
        visited = set()
410
        while to_visit:
411
            pr = to_visit.pop(0)
412
            if pr in visited: continue
413
            visited.add(pr)
414
            yield pr
415
            to_visit += cls.query.find(dict(roles=pr._id)).all()
416
375
    def users_with_role(self):
417
    def users_with_role(self):
376
        return [pr.user for pr in ProjectRole.query.find({'roles':self._id}).all() if pr.user_id]
418
        return [
419
            role.user for role in self.roles_that_reach(self) if role.user_id ]
377
420
378
    def role_iter(self, visited=None):
421
    def role_iter(self):
379
        if visited is None: visited = set()
422
        return self.roles_reachable_from(self)
380
        if self._id not in visited: 
381
            yield self
382
            visited.add(self._id)
383
            for rid in self.roles:
384
                pr = ProjectRole.query.get(_id=rid)
385
                if pr is None: continue
386
                for rr in pr.role_iter(visited):
387
                    yield rr
388
423