web2py

Identify specific group content with auth_membership.group_id


I can get registered users to view only what they post and not what others post, below is the simple code i used. What i want now is how to get only members of groups to view only what their group members post and not members of other groups: How can I change my postedDetails controller to be able to achieve that?

MODEL

db.define_table('post',
            Field('body', 'text', requires=IS_NOT_EMPTY(), label='What is on your mind'),
            Field('posted_on', 'datetime', default=request.now, readable=False, writable=False),
            Field('posted_by', 'reference auth_user', default=auth.user_id, readable=False, writable=False))

CONTROLLER

@auth.requires_membership('firstGroup')
def index():
    form=SQLFORM(db.post)
    if form.process().accepted:
        response.flash=T('Entered')
    return locals()

@auth.requires_membership('firstGroup')
def postedDetails():
    user=db.auth_user(auth.user_id)
    if not user or not(user.id==auth.user_id): redirect(URL('index'))
    details=db(db.post.posted_by==user.id).select(db.post.ALL)
    return locals()

VIEWS

index

{{extend 'layout.html'}}
{{=form}}
{{pass}

postedDetails

{{extend 'layout.html'}}
{{for details in details:}}
Post: {{=details.body}}<br />
Date & Time of Post: {{=details.posted_on}}<br />
Posted By: {{=details.posted_by.first_name}}<br />
{{pass}}

Regards:

Mostwanted


Solution

  • Because the group associated with the post must be frozen at the time of post creation, you should add the group to the post record:

    In the model file:

    def get_group():
        groups = auth.user_groups
        if not groups:
            return None
        group_ids = [id for id in groups if not groups[id].startswith('user_')]
        return group_ids[0] if group_ids else None
    
    db.define_table('post',
        Field('body', 'text', requires=IS_NOT_EMPTY(), label='What is on your mind'),
        Field('posted_on', 'datetime', default=request.now, readable=False, writable=False),
        Field('posted_by', 'reference auth_user', default=auth.user_id,
              readable=False, writable=False),
        Field('group', 'reference auth_group', default=get_group()
    

    Note, auth.user_groups is a dictionary with the IDs of groups the user belongs to as keys and the associated roles as values. It is stored in the session and updated whenever auth.add_membership and auth.del_membership are called. By default, in addition to any groups you set up, each user will have a personal group that starts with "user_", so the above get_group function filters out that group and returns the ID of the remaining group in auth.user_groups, using that value as the default for the db.post.group field.

    Then, in the controller:

    @auth.requires_membership('firstGroup')
    def postedDetails():
        user_group = get_group()
        details = db(db.post.group == user_group).select()
        return locals()
    

    As an aside, in your original code:

    @auth.requires_membership('firstGroup')
    def postedDetails():
        user=db.auth_user(auth.user_id)
        if not user or not(user.id==auth.user_id): redirect(URL('index'))
        details=db(db.post.posted_by==user.id).select(db.post.ALL)
        return locals()
    

    First, auth.user_id is already the ID of the user, so there is no reason to call db.auth_user(auth.user_id) just to get the ID. In fact, auth.user is the user record from db.auth_user, so in general, there is no reason to call db.auth_user(auth.user_id), even if you need other fields in the record.

    Second, auth.requires_membership also requires login, so the second line of the original function that checks for the user and redirects otherwise is not necessary.