Ejemplo n.º 1
0
def follower_invite_trusted(followed, follower, delay_commit=False):
    followed = get_member(followed)
    follower = get_member(follower)

    if not followed:
        raise action_error(_('unable to find followed'), code=404)
    if not follower:
        raise action_error(_('unable to find follower'), code=404)
    if follower == followed:
        raise action_error(_('may not follow yourself'), code=400)
    #if followed in follower.following:
    if follower.is_following(followed):
        raise action_error(_('already following'), code=400)
    if follower.is_follow_trusted_inviter(followed):
        raise action_error(_('already invited to follow as trusted'))

    follow = Follow()
    follow.member = followed
    follow.follower = follower
    follow.type = 'trusted_invite'
    Session.add(follow)

    if not delay_commit:
        Session.commit()

    #invalidate_member(follower)
    #invalidate_member(followed)

    follower.send_notification(
        messages.follow_invite_trusted(member=followed, you=follower))

    return True
Ejemplo n.º 2
0
def associate_janrain_account(user, type, token):
    """
    Associate a login record for a Janrain account
    This is called at:
        1.) Registration
        2.) Linking multiple login accounts to a single Civicboom account
    """
    login = None
    try:
        login = Session.query(UserLogin).filter(UserLogin.token == token).filter(UserLogin.type == type).one()
    except:
        pass
    if login:
        if login.user == user:
            return # If login already belongs to this user then abort
        if login.user: # Warn existing user that account is being reallocated
            login.user.send_email(subject=_('login account reallocated'), content_text=_('your %s account has been allocated to the user %s') % (type, user.username))
        if not config['development_mode']:
            janrain('unmap', identifier=login.token, primaryKey=login.member_id)
        login.user   = user
    else:
        login = UserLogin()
        login.user   = user
        login.type   = type
        login.token  = token
        Session.add(login)
    Session.commit()
    if not config['development_mode']:
        janrain('map', identifier=login.token, primaryKey=login.member_id) # Let janrain know this users primary key id, this is needed for agrigation posts
Ejemplo n.º 3
0
def parent_disassociate(content, delay_commit=False):
    if not content.parent:
        return False

    # Update has to be done before the commit in this case bcause the parent is needed
    #invalidate_content(content.parent) # Could update responses in the future, but for now we just invalidate the whole content
    #invalidate_content(content)        # this currently has code to update parents reponses, is the line above needed?

    if content.__type__ == 'comment':
        content.creator.send_notification(
            messages.comment_dissassociated(
                parentcreator=content.parent.creator,
                parentcontent=content.parent))
        content.visible = False
    else:
        content.creator.send_notification(
            messages.article_disassociated_from_assignment(
                member=content.parent.creator,
                article=content,
                assignment=content.parent))
        # TODO: what if an assignment is dissasocaited from an assignment?
        if content.__type__ == 'article':
            content.approval = "dissassociated"
        content.parent = None

    if not delay_commit:
        Session.commit()

    return True
Ejemplo n.º 4
0
def withdraw_assignemnt(assignment, member, delay_commit=False):
    member = get_member(member)
    assignment = get_content(assignment)

    if not member:
        raise action_error(_("cant find user"), code=404)
    if not assignment:
        raise action_error(_("cant find assignment"), code=404)

    try:
        assignment_accepted = Session.query(MemberAssignment).filter_by(
            member_id=member.id, content_id=assignment.id,
            status="accepted").one()
        assignment_accepted.status = "withdrawn"
        #Session.update(assignment_accepted)
        Session.commit()
        #invalidate_accepted_assignment(member)

        assignment.creator.send_notification(
            messages.assignment_interest_withdrawn(member=member,
                                                   assignment=assignment,
                                                   you=assignment.creator))

        return True
    except:
        pass
    return False
Ejemplo n.º 5
0
def rate_content(content, member, rating):
    content = get_content(content)
    member = get_member(member)
    rating_value = int(rating)

    if not content:
        raise action_error(_('unable to find content'), code=404)
    if not member:
        raise action_error(_('unable to find member'), code=404)
    if rating and rating_value < 0 or rating_value > 5:
        raise action_error(_("Ratings can only be in the range 0 to 5"),
                           code=400)

    # remove any existing ratings
    # we need to commit after removal, otherwise SQLAlchemy
    # will optimise remove->add as modify-existing, and the
    # SQL trigger will break
    try:
        existing = Session.query(Rating).filter(
            Rating.content == content).filter(Rating.member == member).one()
        Session.delete(existing)
        Session.commit()
    except NoResultFound:
        pass

    # rating = 0 = remove vote
    # add a new one
    if rating_value > 0:
        r = Rating()
        r.content = content
        r.member = member
        r.rating = rating_value
        Session.add(r)
        Session.commit()
Ejemplo n.º 6
0
def unfollow(follower, followed, delay_commit=False):
    followed = get_member(followed)
    follower = get_member(follower)

    if not followed:
        raise action_error(_('unable to find followed'), code=404)
    if not follower:
        raise action_error(_('unable to find follower'), code=404)
    #if followed not in follower.following:
    # GregM: can unfollow to remove trusted invite
    if not follower.is_following(
            followed) and not follower.is_follow_trusted_inviter(followed):
        raise action_error(_('not currently following'), code=400)

    #follower.following.remove(followed)
    follow = Session.query(Follow).filter(
        Follow.member_id == followed.id).filter(
            Follow.follower_id == follower.id).one()
    Session.delete(follow)

    if not delay_commit:
        Session.commit()

    #invalidate_member(follower)
    #invalidate_member(followed)

    followed.send_notification(
        messages.follow_stop(member=follower, you=followed))

    return True
Ejemplo n.º 7
0
def set_password(user, new_token, delay_commit=False):
    """
    Set password
    WARNING! We assume the user has already been authenticated
    - remove old password (if found)
    - create new password record
    """
    # search for existing record and remove it
    #
    try:
        for existing_login in [login for login in user.login_details if login.type == 'password']:
            log.debug("removing password for %s" % user.username)
            #if existing_login.token == old_token: raise Exception('old password token does not match - aborting password change')
            Session.delete(existing_login)
            log.debug("removed ok")
    #try: Session.execute(UserLogin.__table__.delete().where(and_(UserLogin.__table__.c.member_id == user.id, UserLogin.__table__.c.token == token)))
    except Exception:
        pass
    # Set new password
    u_login = UserLogin()
    u_login.user   = user
    u_login.type   = 'password'
    u_login.token  = new_token
    Session.add(u_login)
    
    if not delay_commit:
        Session.commit()
Ejemplo n.º 8
0
def follower_distrust(followed, follower, delay_commit=False):
    followed = get_member(followed)
    follower = get_member(follower)

    if not followed:
        raise action_error(_('unable to find followed'), code=404)
    if not follower:
        raise action_error(_('unable to find follower'), code=404)
    if not follower.is_following(followed):
        raise action_error(_('not currently following'), code=400)

    follow = Session.query(Follow).filter(
        Follow.member_id == followed.id).filter(
            Follow.follower_id == follower.id).one()
    if not follow:
        raise action_error(_('member is not a follower'), code=404)
    if follow.type == 'trusted':
        follow.type = 'normal'
    elif follow.type == 'trusted_invite':
        raise action_error(_('follower still has pending invite'), code=400)
    elif follow.type == 'normal':
        raise action_error(_('follower was not trusted'), code=400)

    if not delay_commit:
        Session.commit()

    # invalidate_member(follower) # GregM: Needed?
    # invalidate_member(followed) # GregM: Needed?

    follower.send_notification(
        messages.follower_distrusted(member=followed, you=follower))

    return True
Ejemplo n.º 9
0
def respond_assignment(parent_content, member, delay_commit=False):
    """
    When creating a response, the accepted record should be flagged as responded
    """
    member = get_member(member)
    parent_content = get_content(parent_content)

    if not member:
        raise action_error(_("cant find user"), code=404)
    if not parent_content:
        raise action_error(_("cant find parent content"), code=404)

    if parent_content.__type__ != 'assignment':
        return  # Nothing to do if parent is not assignment

    try:
        # upgrade an 'accepted' record to 'responded'
        member_assignment = Session.query(MemberAssignment).filter_by(
            member_id=member.id, content_id=parent_content.id).one()
        member_assignment.status = "responded"
    except:
        # otherwise create 'responded' record
        member_assignment = MemberAssignment()
        member_assignment.content = parent_content
        member_assignment.member = member
        #assignment_accepted.member_id = member.id
        member_assignment.status = "responded"
        Session.add(member_assignment)

    if not delay_commit:
        Session.commit()

    #invalidate_accepted_assignment(member)
    return True
Ejemplo n.º 10
0
def payment_member_remove(payment_account, member):
    member = get_member(member)
    if not member.payment_account == payment_account:
        return False
    member.payment_account = None
    Session.commit()
    return True
Ejemplo n.º 11
0
def payment_member_add(payment_account, member):
    member = get_member(member)
    if member.payment_account:
        return False
    member.payment_account = payment_account
    Session.commit()
    return True
Ejemplo n.º 12
0
def parent_approve(content, delay_commit=False):

    content.edit_lock = "parent_owner"
    content.approval = "approved"

    # AllanC - the direct email notifications were removed. They have now been replaced by the notification system
    # Email content parent & content creator
    #from pylons import tmpl_context as c # Needed for passing varibles to templates
    #c.content = content
    #content.parent.creator.send_email(subject=_('content request' ), content_html=render('/email/approve_lock/lock_article_to_organisation.mako'))
    #content.creator.send_email(       subject=_('content approved'), content_html=render('/email/approve_lock/lock_article_to_member.mako'))

    # Generate notifications - these have custom email templates that override the base notification
    extra_vars = {
        'content_id': content.id
    }  #extra variables for template rendering
    content.creator.send_notification(
        messages.article_approved_creator(member=content.parent.creator,
                                          parent=content.parent,
                                          content=content),
        extra_vars=extra_vars)  #, delay_commit=True
    content.parent.creator.send_notification(
        messages.article_approved_parent(member=content.parent.creator,
                                         parent=content.parent,
                                         content=content),
        extra_vars=extra_vars)  #, delay_commit=True

    if not delay_commit:
        Session.commit()

    #invalidate_content(content)
    return True
Ejemplo n.º 13
0
 def viewable_by(self, member):
     """
     Check to see if a member object has the rights to view this content
     """
     # TODO check groups of creator to see if member is in the owning group
     if self.editable_by(member):
         return True  # Always allow content to be viewed by owners/editors
     if self.__type__ == "draft":
         return False  # if draft, only editors (above) can see
     if self.__type__ == "comment":
         return self.parent.viewable_by(
             member)  # if comment, show if we can see the parent article
     if self.visible == True:
         # GregM: If current content has a root parent then check viewable_by on root parent
         root = self.root_parent
         if root:
             return root.viewable_by(member)
         # GregM: If content is private check member is a trusted follower of content's creator
         #       We NEED to check has accepted, invited etc. for requests
         if self.private == True:
             if self.creator.is_follower_trusted(member):
                 return True
             elif self.__type__ == "assignment":
                 from civicboom.lib.database.get_cached import get_assigned_to
                 member_assignment = get_assigned_to(self, member)
                 if member_assignment:
                     if not member_assignment.member_viewed:
                         from civicboom.model.meta import Session
                         member_assignment.member_viewed = True
                         Session.commit()
                     return True
             return False
         return True
     return False
Ejemplo n.º 14
0
def del_group(group):
    group = get_group(group)
    from pylons import tmpl_context as c
    for member in [member_role.member for member_role in group.members_roles]:
        member.send_notification(
            messages.group_deleted(group=group, admin=c.logged_in_user)
        )  # AllanC - We cant use the standard group.send_notification because the group wont exisit after this line!
    Session.delete(group)
    Session.commit()
Ejemplo n.º 15
0
def parent_seen(content, delay_commit=False):
    content.edit_lock = "parent_owner"
    content.approval = "seen"

    # AllanC - TODO generate notification
    #content.creator.send_notification(???, delay_commit=True)

    if not delay_commit:
        Session.commit()
    #invalidate_content(content)
    return True
Ejemplo n.º 16
0
def unboom_content(content, member, delay_commit=False):
    boom = has_boomed(content, member)
    if boom:
        Session.delete(boom)
    else:
        raise action_error(_(
            "%s has not boomed previously boomed this _content" % member),
                           code=400)

    if not delay_commit:
        Session.commit()
Ejemplo n.º 17
0
def verify_email_hash(user, hash, commit=False):
    user = get_member(user)
    if user and user.hash() == hash:
        if not config['demo_mode']: # AllanC - Demo mode is ALWAYS offline, there is no way we can validate members emails address's. But the hash is correct so return True
            if user.email_unverified:
                user.email            = user.email_unverified
                user.email_unverified = None
            if commit:
                Session.commit()
        return True
    return False
Ejemplo n.º 18
0
 def part_pay_invoice_manual(self, invoice, amount=None):
     """
     Create a manual transaction against invoice
     """
     txn = BillingTransaction()
     txn.invoice = invoice
     txn.status = 'complete'
     txn.amount = amount or invoice.total_due
     txn.provider = 'manual_test'
     txn.reference = 'test'
     Session.commit()
     pass
Ejemplo n.º 19
0
def morph_content_to(content, after_type):
    """
    params:
        content can be a Content object or a string id
            - as this works at the database level, any content data not commited to the DB before this call will be lost
        after_type is a string of the type the object is being transformed too
        
    return:
        the new mophed object from the database
        
    Notes:
    This is a VERY expensive operation as it requires up to 3 calls to get_content,
    each of these calls is joining potentialy over 3 tables
    """
    
    content = get_content(content)
    if not content:
        raise Exception('no content to morph')
    
    if content.__type__ == None:
        return content # If we don't know the source object type then we cant process it
    if content.__type__ == after_type:
        return content # If the before and after types are the same then return the content obj as no processing needs to take place
    
    if content.id == None: # If the content has not been commited to the DB
        # then return an object of the correct type?
        # todo? 
        #log.warn('content to morph not in DB? investigate')
        raise Exception('content to morph not in DB? investigate')
    
    id                = content.id
    prev_type         = content.__type__
    sql_generator_key = content.__type__+":"+after_type
    
    if sql_generator_key not in morph_sql:
        raise Exception('unable to morph content from %s to %s' % (content.__type__, after_type) )
    
    Session.expunge(content) # Remove content from SQLAlchemys scope
    for sql_cmd in morph_sql[sql_generator_key](id):
        Session.execute(sql_cmd)
    Session.commit()
    
    content = get_content(id)
    assert content.__type__ == after_type # If this is not true then something has gone very wrong!

    # AllanC - Although the events linked to the commit of this object invalidte the list type for the 'current' content type, they do not take into consideration a content morph from the previous type
    #          In fact .. we need to invalidate the content item manually here because the SQL statement does not associate with the SQLA object and therefor does not trigger the SQLA events
    #          We need to manually invalidate the list that this content object was 'before' the morph
    invalidate_content(content)
    invalidate_content_list(prev_type, content.creator_id)
    
    return content
Ejemplo n.º 20
0
 def delete_content(self, id, force=False):
     if force:  # ignore logged in user and just get rid of it
         Session.delete(Session.query(Content).get(id))
         Session.commit()
     else:
         self.assertIn('delete', self.get_actions(id))
         response = self.app.post(url('content', id=id, format="json"),
                                  params={
                                      '_method': 'delete',
                                      '_authentication_token':
                                      self.auth_token,
                                  },
                                  status=200)
Ejemplo n.º 21
0
def accept_assignment(assignment,
                      member,
                      status="accepted",
                      delay_commit=False):
    member = get_member(member)
    assignment = get_content(assignment)

    if not member:
        raise action_error(_("cant find user"), code=404)
    if not assignment:
        raise action_error(_("cant find assignment"), code=404)
    if not issubclass(assignment.__class__, AssignmentContent):
        raise action_error(_("only _assignments can be accepted"), code=400)
    # all permissins hendled by controler action - so this is unneeded here
    #if not assignment.viewable_by(c.logged_in_persona):
    #    raise action_error(_('_assignment is not visible to your user and therefor cannot be accepted'), code=403)
    if assignment_previously_accepted_by(assignment, member):
        raise action_error(_(
            '_assignment has been previously accepted and cannot be accepted again'
        ),
                           code=400)
    #if assignment.creator == member:
    #    raise action_error(_("cannot accept your own _assignment"), code=400)

    assignment_accepted = MemberAssignment()
    assignment.assigned_to.append(assignment_accepted)
    assignment_accepted.member = member
    assignment_accepted.status = status
    Session.add(assignment_accepted)

    if not delay_commit:
        Session.commit()
    #invalidate_accepted_assignment(member)

    if status == "accepted":
        assignment.creator.send_notification(
            messages.assignment_accepted(member=member,
                                         assignment=assignment,
                                         you=assignment.creator))
    if status == "pending":
        member.send_notification(
            messages.assignment_invite(member=assignment.creator,
                                       assignment=assignment,
                                       you=member))

    return True
Ejemplo n.º 22
0
 def mark_messages_as_read(self, **kwargs):
     """
     POST /profile/{id}/mark_messages_as_read: Mark messages as read
     @type action
     @api contents 1.0 (WIP)
     
     @param type   type of message object to mark as read from all, to, notification
     """
     list_type = kwargs.get('list', 'all')
     if list_type in list_filters and list_type in ['all','to','notification']:
         results = Session.query(Message).filter(Message.target_id==c.logged_in_persona.id)
         results = list_filters[list_type](results)
         for message in results.all():
             message.read = True
         Session.commit()
         return action_ok(message='%s marked as read' % type, code=201)
     raise action_error(_('list %s not supported') % kwargs.get('list'), code=400)
Ejemplo n.º 23
0
def remove_member(group, member, delay_commit=False):
    group = get_group(group)
    member = get_member(member)
    membership = get_membership(group, member)

    if not group:
        raise action_error(_('unable to find group'), code=404)
    if not member:
        raise action_error(_('unable to find member'), code=404)
    if not membership:
        raise action_error(_('not a member of group'), code=400)
    # AllanC - permissions moved to controller
    #if member!=c.logged_in_persona and not group.is_admin(c.logged_in_persona):
    #    raise action_error('current user has no permissions for this group', 403)
    #AllanC - integrety moved to model
    #if membership.role=="admin" and num_admins<=1:
    #    raise action_error('cannot remove last admin', 400)

    # Notifications
    if membership.status == "active":  # member removed
        from pylons import tmpl_context as c
        if member != c.logged_in_user:
            membership.member.send_notification(
                messages.group_remove_member_to_member(admin=c.logged_in_user,
                                                       group=group))
        group.send_notification(
            messages.group_remove_member_to_group(admin=c.logged_in_user,
                                                  group=group,
                                                  member=member))
    elif membership.status == "invite":  # invitation declined
        group.send_notification(
            messages.group_invitation_declined(member=member, group=group))
    elif membership.status == "request":  # request declined
        membership.member.send_notification(
            messages.group_request_declined(group=group))

    Session.delete(membership)

    if not delay_commit:
        Session.commit()

    #invalidate_member(group)
    #invalidate_member(member)

    return True
Ejemplo n.º 24
0
def set_role(group, member, role, delay_commit=False):
    group = get_group(group)
    member = get_member(member)
    membership = get_membership(group, member)
    role = role or membership.role or group.default_role

    if not group:
        raise action_error(_('unable to find group'), code=404)
    if not member:
        raise action_error(_('unable to find member'), code=404)
    if not membership:
        raise action_error(_('not a member of group'), code=400)
    if role not in group_member_roles.enums:
        raise action_error('not a valid role', code=400)
    # AllanC - permisions moved to controller
    #if not group.is_admin(c.logged_in_persona):
    #    raise action_error(_('no permissions for this group'), 403)
    # AllanC - integrtiy moved to model
    #if membership.role=="admin" and num_admins<=1:
    #    raise action_error('cannot remove last admin', 400)

    from pylons import tmpl_context as c
    membership.role = role
    if membership.status == "request":
        membership.status = "active"
        member.send_notification(
            messages.group_request_accepted(admin=c.logged_in_user,
                                            group=group,
                                            you=member))
        group.send_notification(
            messages.group_new_member(member=member, group=group))
    else:
        group.send_notification(
            messages.group_role_changed(admin=c.logged_in_user,
                                        member=member,
                                        group=group,
                                        role=role))

    if not delay_commit:
        Session.commit()

    #invalidate_member(group)
    #invalidate_member(member)

    return True
Ejemplo n.º 25
0
def set_payment_account(member, value, delay_commit=False):
    member = get_member(member)
    #account = None
    if isinstance(value, PaymentAccount):
        member.payment_account = value
    elif value in account_types.enums:
        if value == 'free':
            account = None
        else:
            account = PaymentAccount()
            account.type = value
            Session.add(account)
        member.payment_account = account
    else:
        raise action_error('unknown account type: %s' % value)
    if not delay_commit:
        Session.commit()
    return True
Ejemplo n.º 26
0
def add_to_interests(member, content, delay_commit=False):
    content = get_content(content)
    member = get_member(member)

    if not content:
        raise action_error(_('unable to find content'), code=404)
    if not member:
        raise action_error(_('unable to find member'), code=404)

    #AllanC - TODO: humm ... if we have a duplicate entry being added it will error ... we want to suppress that error

    member.interest.append(content)

    # Could update "recomended" feed with new criteria?

    if not delay_commit:
        Session.commit()

    return True
Ejemplo n.º 27
0
    def invite(self, members, **kwargs):
        """
        For closed assignments we need to invite specific members to participate
        invite can be given a single member or a list of members (as username strings or member object list)
        """
        from civicboom.lib.database.actions import accept_assignment
        from civicboom.model.meta import Session

        def invite_member(member):
            return accept_assignment(self,
                                     member,
                                     status="pending",
                                     delay_commit=True)

        if isinstance(members, list):
            for member in members:
                invite_member(member)
        else:
            invite_member(members)
        Session.commit()
Ejemplo n.º 28
0
def join_group(group, member, delay_commit=False):
    return_value = True

    group = get_group(group)
    member = get_member(member)
    membership = get_membership(group, member)

    if not group:
        raise action_error(_('unable to find group'), code=404)
    if not member:
        raise action_error(_('unable to find member to add'), code=404)
    # AllanC - join permissions moved to controller

    if membership and membership.status == "invite":
        membership.status = "active"
    else:
        membership = GroupMembership()
        membership.group = group
        membership.member = member
        membership.role = group.default_role
        group.members_roles.append(membership)

        # If a join request
        if group.join_mode == "invite_and_request":
            membership.status = "request"
            return_value = "request"
            group.send_notification(
                messages.group_join_request(member=member, group=group))

    # If user has actually become a member (open or reply to invite) then notify group
    if return_value == True:
        group.send_notification(
            messages.group_new_member(member=member, group=group))

    if not delay_commit:
        Session.commit()

    #invalidate_member(group)
    #invalidate_member(member)

    return return_value
Ejemplo n.º 29
0
def follow(follower, followed, delay_commit=False):
    followed = get_member(followed)
    follower = get_member(follower)

    if not followed:
        raise action_error(_('unable to find followed'), code=404)
    if not follower:
        raise action_error(_('unable to find follower'), code=404)
    if follower == followed:
        raise action_error(_('may not follow yourself'), code=400)
    #if followed in follower.following:
    if follower.is_following(followed):
        raise action_error(_('already following'), code=400)

    # AllanC - I wanted to use is_following and remove the following reference - but as this code is run by base test populator before the site is running it cant be

    # GregM: Change invite to follow if is invited, otherwise follow:
    if follower.is_follow_trusted_inviter(followed):
        follow = Session.query(Follow).filter(
            Follow.member_id == followed.id).filter(
                Follow.follower_id == follower.id).filter(
                    Follow.type == 'trusted_invite').one()
        follow.type = 'trusted'
    else:
        #follower.following.append(followed)
        follow = Follow()
        follow.member = followed
        follow.follower = follower
        Session.add(follow)

    if not delay_commit:
        Session.commit()

    #invalidate_member(follower)
    #invalidate_member(followed)

    followed.send_notification(
        messages.followed_by(member=follower, you=followed))

    return True
Ejemplo n.º 30
0
def invite(group, member, role, delay_commit=False):
    group = get_group(group)
    member = get_member(member)
    membership = get_membership(group, member)
    role = role or group.default_role

    if not group:
        raise action_error(_('unable to find group'), code=404)
    if not member:
        raise action_error(_('unable to find member'), code=404)
    if membership:
        raise action_error(_('already a member of group'), code=400)
    if role not in group_member_roles.enums:
        raise action_error('not a valid role', code=400)
    # AllanC - permissions moved to controller
    #if not group.is_admin(c.logged_in_persona):
    #    raise action_error(_('no permissions for this group'), 403)

    membership = GroupMembership()
    membership.group = group
    membership.member = member
    membership.role = role
    membership.status = "invite"
    group.members_roles.append(membership)

    # Notification of invitation
    from pylons import tmpl_context as c
    member.send_notification(
        messages.group_invite(admin=c.logged_in_user,
                              group=group,
                              role=membership.role,
                              you=member))

    if not delay_commit:
        Session.commit()

    #invalidate_member(group)
    #invalidate_member(member)

    return True