Esempio n. 1
0
def gen_extracts(change, tmp_filepath):
    """
    Will generate the file extracts for this change. The extracts include the thumbnail.
    
    :param change: is the change object.
    :param tmp_filepath: is the path to the original file
    """

    # find previous change
    previous = change.entity.get_change(version=change.version - 1)

    extracts = []
    indices = dd(lambda: 0)  #each type of file will have its own count
    raw_extracts, parse_info = image.extract(tmp_filepath)
    change.file_type = parse_info.file_type
    raw_extracts += gen_diffs(previous, raw_extracts)
    for e in raw_extracts:

        change_extract = projects.ChangeExtract(
            change=change,
            extract_type=e.extract_type,
            order_index=indices[e.extract_type])
        change_extract.set_contents(e.filename)
        Session.add(change_extract)
        extracts.append(change_extract)

        indices[e.extract_type] += 1

    change.parse_type = parse_info.type
    change.parse_status = parse_info.status

    commit()
    return extracts
Esempio n. 2
0
def create(**params):
    """
    Creates a user.
    
    DO NOT EXPOSE THIS to the web api. Please.
    """
    numusers = len(Session.query(users.User).all())

    scrubbed = validate(RegisterForm, **params)
    logger.info(scrubbed)

    user = users.User()
    Session.add(user)

    user.email = scrubbed.email
    user.username = '******' in scrubbed and scrubbed.username or scrubbed.email
    user.password = scrubbed.password
    user.set_timezone_int(scrubbed.default_timezone)

    if scrubbed.get('name'):
        name = scrubbed.get('name').split(' ', 1)
        user.first_name = name[0].strip()
        user.last_name = len(name) == 2 and name[1].strip() or u''
    else:
        user.first_name = scrubbed.get('first_name')
        user.last_name = scrubbed.get('last_name')

    #first user is an admin.
    if numusers == 0:
        user.role = users.ROLE_ADMIN

    return user
Esempio n. 3
0
def create(**params):
    """
    Creates a user.
    
    DO NOT EXPOSE THIS to the web api. Please.
    """
    numusers = len(Session.query(users.User).all())

    scrubbed = validate(RegisterForm, **params)
    logger.info(scrubbed)

    user = users.User()
    Session.add(user)
    
    user.email = scrubbed.email
    user.username = '******' in scrubbed and scrubbed.username or scrubbed.email
    user.password = scrubbed.password
    user.set_timezone_int(scrubbed.default_timezone)
    
    if scrubbed.get('name'):
        name = scrubbed.get('name').split(' ', 1)
        user.first_name = name[0].strip()
        user.last_name = len(name) == 2 and name[1].strip() or u''
    else:
        user.first_name = scrubbed.get('first_name')
        user.last_name = scrubbed.get('last_name')
    
    #first user is an admin. 
    if numusers == 0:
        user.role = users.ROLE_ADMIN
    
    return user
Esempio n. 4
0
def upload_extract(real_user, user, change, **kw):
    """
    File is binary in the request body.
    """
    
    from pylons import request
    order_index = int(to_unicode(request.headers.get('X-Up-Order-Index')))
    type = to_unicode(request.headers.get('X-Up-Type'))
    
    if not type: return None
    
    f, tmpname = tempfile.mkstemp('png')
    if isinstance(f, int):
        f = open(tmpname, 'wb')
    
    #this is inefficient. Pylons supposedly already creates a tmp file. We are instead
    #reading the thing into memory. I'm lazy until this beomes an issue (prolly soon)
    #V: please make this not suck
    f.write(request.environ['wsgi.input'].read())
    f.close()
    
    new = False
    change_extract = Session.query(projects.ChangeExtract).filter_by(change=change, extract_type=type, order_index=order_index).first()
    if not change_extract:
        new = True
        change_extract = projects.ChangeExtract(change=change, extract_type=type, order_index=order_index)
        Session.add(change_extract)
    
    change_extract.set_contents(tmpname)
    
    return new and 'new' or 'existing'
Esempio n. 5
0
def gen_extracts(change, tmp_filepath):
    """
    Will generate the file extracts for this change. The extracts include the thumbnail.
    
    :param change: is the change object.
    :param tmp_filepath: is the path to the original file
    """
    
    # find previous change
    previous = change.entity.get_change(version=change.version-1)
    
    extracts = []
    indices = dd(lambda: 0) #each type of file will have its own count
    raw_extracts, parse_info = image.extract(tmp_filepath)
    change.file_type = parse_info.file_type
    raw_extracts += gen_diffs(previous, raw_extracts)
    for e in raw_extracts:
        
        change_extract = projects.ChangeExtract(change=change, extract_type=e.extract_type, order_index=indices[e.extract_type])
        change_extract.set_contents(e.filename)
        Session.add(change_extract)
        extracts.append(change_extract)
        
        indices[e.extract_type] += 1
    
    change.parse_type = parse_info.type
    change.parse_status = parse_info.status
    
    commit()
    return extracts
Esempio n. 6
0
def create(real_user, user, organization, **params):
    """
    Creates a project.
    """
    class ProjectForm(formencode.Schema):
        name = formencode.All(fv.UnicodeString(not_empty=True), UniqueName(organization))
        description = fv.UnicodeString(not_empty=False)
    
    scrubbed = validate(ProjectForm, **params)

    project = projects.Project(name=scrubbed.name,
                               creator=user,
                               description=scrubbed.description,
                               organization=organization)
    Session.add(project)
    Session.flush()
    
    #email
    users = organization.interested_users
    if user in users: users.remove(user)
    email.send(users, 'create_project.txt', {
        'project': project,
        'creator': user
    })
    
    return project
Esempio n. 7
0
def edit(real_user, user, file, **kwargs):
    """
    Editing of the campaigns. Supports editing one param at a time. Uses the FieldEditor
    paradigm.
    """
    editor = Editor(file)
    editor.edit(real_user, user, file, **kwargs)
    Session.flush()
    Session.refresh(file)
    return file
Esempio n. 8
0
def edit(real_user, user, change, **kwargs):
    """
    Editing of the campaigns. Supports editing one param at a time. Uses the FieldEditor
    paradigm.
    """
    editor = Editor()
    editor.edit(real_user, user, change, **kwargs)
    Session.flush()
    Session.refresh(change)
    return change
Esempio n. 9
0
def create_project(user=None, organization=None, role=users.APP_ROLE_ADMIN, **kw):
    kw.setdefault("name", create_unique_str(u'project'))
    kw.setdefault("description", create_unique_str(u"description"))
    kw.setdefault("status", STATUS_APPROVED)

    org = organization or create_organization(user, role)

    project = projects.Project(organization=org, creator=user or org.creator, **kw)
    Session.add(project)
    Session.flush()

    return project
Esempio n. 10
0
def create_user(is_admin=False, **kw):

    kw.setdefault("email", create_email_address())
    kw.setdefault("username", create_unique_str(u'user', extra=u''))
    kw.setdefault("password", u'testpassword')
    
    if is_admin:
        kw.setdefault("role", users.ROLE_ADMIN)
    else:
        kw.setdefault("role", users.ROLE_USER)

    user = users.User(**kw)
    Session.add(user)
    Session.flush()
    return user
Esempio n. 11
0
def project_user_module(real_user, user, organization, project=None):
    """
    """
    # email: user def list
    org_users = api.organization.get_users(real_user, user, organization, status=STATUS_APPROVED)
    user_map = dict([(ou.user.email, v1.user.get().output(ou.user)) for ou in org_users])
    
    #email list for lookup
    emails = [u.user.email for u in org_users]
    
    # list of users in the project and their role
    invite_url = None
    proj_users = []
    if project:
        invites = Session.query(users.Invite).filter_by(type=users.INVITE_TYPE_PROJECT, object_id=project.id, status=STATUS_PENDING)
        invites = [{'invite': True, 'user': {'name': i.invited_email}} for i in invites]
        proj_users = api.project.get_users(real_user, user, project, status=STATUS_APPROVED)
        proj_users = v1.project.get_users().output(proj_users) + invites
        invite_url = h.api_url('invite', 'create', project=c.project.eid)
    
    params = {
        'emails': emails,
        'projectUsers': proj_users,
        'userMap': user_map,
        'roleUrl': h.api_url('project', 'set_user_role', project=project and project.eid or None),
        'syncUrl': h.api_url('project', 'attach_users'),
        'inviteUrl': invite_url
    }
    
    return params
Esempio n. 12
0
def create_organization(user=None, role=users.APP_ROLE_ADMIN, status=STATUS_APPROVED, **kw):
    """
    create an org and will attach a user to it. If no user specified, will make one.
    """
    kw.setdefault("name", create_unique_str(u'org'))
    kw.setdefault("url", u'http://%s.com' % create_unique_str(u'url'))
    kw.setdefault("subdomain", create_str(length=10))
    
    user = user or create_user()
    
    org = users.Organization(creator=user, **kw)
    Session.add(org)
    
    #connect user to org as admin of org
    org_user = org.attach_user(user, role=role, status=status)
    Session.flush()
    
    return org
Esempio n. 13
0
def get(u=None, username=None):
    if not u and not username:
        abort(403)
    elif u: return u
    
    u = Session.query(users.User).filter_by(username=username).first()
    if not u:
        abort(403)
    
    return u
Esempio n. 14
0
 def _to_python(self, value, state):
     # we don't support multiple values, so we run a quick check here (we got a webapp where this was a problem)
     if type(value) != type(u""):
         raise fv.Invalid('You must supply a valid email.', value, state)
     
     user = Session.query(users.User).filter(sa.func.lower(users.User.email)==value.lower()).first()
     # if this user is the same as the logged in one then don't throw the error - allows keeping old email address when editing contact info
     if user and user != self.user:
         raise fv.Invalid('That user already exists. Please choose another.', value, state)
     return value
Esempio n. 15
0
 def _to_python(self, value, state):
     
     if type(value) != type(u""):
         raise fv.Invalid('You must supply a valid subdomain.', value, state)
     
     subd = Session.query(users.Organization).filter(sa.func.lower(users.Organization.subdomain)==value.lower()).first()
     
     if subd:
         raise fv.Invalid('%s is already taken' % value, value, state)
     
     return value.lower()
Esempio n. 16
0
def get(u=None, username=None):
    if not u and not username:
        abort(403)
    elif u:
        return u

    u = Session.query(users.User).filter_by(username=username).first()
    if not u:
        abort(403)

    return u
Esempio n. 17
0
def get(real_user, user, organization, project=None):
    if not user and not project:
        abort(403)
    
    if project:
        q = Session.query(projects.Project).filter_by(organization=organization)
        p = q.filter(sa.or_(projects.Project.eid==project, projects.Project.slug==project)).first()
        CanReadProject().check(real_user, user, project=p)
        return p
    
    #this will do the check to make sure to return only projects the user can see
    return organization.get_projects(user)
Esempio n. 18
0
def get(real_user=None, user=None, organization=None, subdomain=None):
    """
    get a single project, or all the user's projects
    """
    if organization:
        CanReadOrg().check(real_user, user, organization=organization)
        return organization
    
    elif subdomain:
        return Session.query(users.Organization).filter_by(subdomain=subdomain).first()
    
    return user.get_organizations()
Esempio n. 19
0
def get(real_user=None, user=None, organization=None, subdomain=None):
    """
    get a single project, or all the user's projects
    """
    if organization:
        CanReadOrg().check(real_user, user, organization=organization)
        return organization

    elif subdomain:
        return Session.query(
            users.Organization).filter_by(subdomain=subdomain).first()

    return user.get_organizations()
Esempio n. 20
0
    def _to_python(self, value, state):
        # we don't support multiple values, so we run a quick check here (we got a webapp where this was a problem)
        if type(value) != type(u""):
            raise fv.Invalid('You must supply a valid email.', value, state)

        user = Session.query(users.User).filter(
            sa.func.lower(users.User.email) == value.lower()).first()
        # if this user is the same as the logged in one then don't throw the error - allows keeping old email address when editing contact info
        if user and user != self.user:
            raise fv.Invalid(
                'That user already exists. Please choose another.', value,
                state)
        return value
Esempio n. 21
0
    def _to_python(self, value, state):

        if type(value) != type(u""):
            raise fv.Invalid('You must supply a valid subdomain.', value,
                             state)

        subd = Session.query(users.Organization).filter(
            sa.func.lower(users.Organization.subdomain) ==
            value.lower()).first()

        if subd:
            raise fv.Invalid('%s is already taken' % value, value, state)

        return value.lower()
Esempio n. 22
0
    def _to_python(self, value, state):
        # we don't support multiple values, so we run a quick check here (we got a webapp where this was a problem)
        if not isinstance(value, unicode):
            raise fv.Invalid('You must supply a valid string.', value, state)

        file = Session.query(projects.Entity
                ).filter(projects.Entity.project==self.project
                ).filter(projects.Entity.path==self.file.path
                ).filter(projects.Entity.name==value
                )
        
        file = file.filter(projects.Entity.id != self.file.id)
        file = file.first()

        if file:
            raise fv.Invalid('A file with this name already exists. Please choose another.', value, state)
        
        return value
Esempio n. 23
0
    def _to_python(self, value, state):
        # we don't support multiple values, so we run a quick check here (we got a webapp where this was a problem)
        if not isinstance(value, unicode):
            raise fv.Invalid('You must supply a valid string.', value, state)

        project = Session.query(projects.Project
                ).filter(projects.Project.organization==self.organization
                ).filter(projects.Project.name==value
                )
        
        if self.project:
            project = project.filter(projects.Project.id != self.project.id)
        
        project = project.first()

        if project:
            raise fv.Invalid('A project with this name already exists. Please choose another.', value, state)
        return value
Esempio n. 24
0
def get(real_user, user, change=None, parse_type=None, parse_status=None):
    
    if change:
        return change

    if not parse_status and not parse_type:
        raise ClientException('either parse_type or parse_status')
    
    q = Session.query(projects.Change)
    if parse_type:
        q = q.filter(projects.Change.parse_type.in_(parse_type))
    
    if parse_status:
        q = q.filter(projects.Change.parse_status.in_(parse_status))
    
    q = q.order_by(sa.asc(projects.Change.created_date))
    
    return q.all()
Esempio n. 25
0
    def _to_python(self, value, state):
        # we don't support multiple values, so we run a quick check here (we got a webapp where this was a problem)
        if not isinstance(value, unicode):
            raise fv.Invalid('You must supply a valid string.', value, state)

        file = Session.query(projects.Entity).filter(
            projects.Entity.project == self.project).filter(
                projects.Entity.path == self.file.path).filter(
                    projects.Entity.name == value)

        file = file.filter(projects.Entity.id != self.file.id)
        file = file.first()

        if file:
            raise fv.Invalid(
                'A file with this name already exists. Please choose another.',
                value, state)

        return value
Esempio n. 26
0
def create(real_user, user, **params):
    """
    Creates an organization. Attaches it to User.
    """

    scrubbed = validate(CreateForm, **params)
    scrubbed.setdefault('is_active', True)

    scrubbed['name'] = scrubbed['company_name']
    del scrubbed['company_name']

    #attach the user as a creator.
    org = users.Organization(creator=user, **scrubbed)
    Session.add(org)

    #connect user to org as admin of org
    org.attach_user(user, role=users.APP_ROLE_ADMIN, status=STATUS_APPROVED)
    Session.add(activity.NewOrganization(user, org))

    Session.flush()
    return org
Esempio n. 27
0
def create(real_user, user, **params):
    """
    Creates an organization. Attaches it to User.
    """
    
    scrubbed = validate(CreateForm, **params)
    scrubbed.setdefault('is_active', True)
    
    scrubbed['name'] = scrubbed['company_name']
    del scrubbed['company_name']
    
    #attach the user as a creator.
    org = users.Organization(creator=user, **scrubbed)
    Session.add(org)
    
    #connect user to org as admin of org
    org.attach_user(user, role=users.APP_ROLE_ADMIN, status=STATUS_APPROVED)
    Session.add(activity.NewOrganization(user, org))
    
    Session.flush()
    return org
Esempio n. 28
0
        indices[e.extract_type] += 1

    change.parse_type = parse_info.type
    change.parse_status = parse_info.status

    commit()
    return extracts


if __name__ == '__main__':
    """
    accept 2 params:
    eid of the change
    path to file, the raw file (PSD, PDF, whatev...)
    """
    if len(sys.argv) != 4:
        print 'Usage: %s development.ini change_eid /path/to/tmp_file.blah' % sys.argv[
            0]
        exit(1)

    ini, eid, filepath = sys.argv[1:]

    load_config(os.path.abspath(ini))

    change = Session.query(projects.Change).filter_by(eid=eid).first()
    if not change:
        print 'Cannot find change %s' % eid
        exit(1)

    print gen_extracts(change, filepath)
Esempio n. 29
0
 def test_all(self):
     
     a = fh.create_user(is_admin=True)
     org_owner = fh.create_user()
     inviteme = fh.create_user(email="*****@*****.**")
     
     org = fh.create_organization(user=org_owner, subdomain='cats', name='CATS!')
     project = fh.create_project(user=org_owner, organization=org, name=u"helloooo")
     change = project.add_change(org_owner, u"/main/project/arnold/foobar.gif", file_path('ffcc00.gif'), u"this is a new change")
     file = change.entity
     self.flush()
     
     email = '*****@*****.**'
     #invite user not in the system to file
     invite = api.invite.create(a, org_owner, email, entity=file)
     
     #based on email only
     assert self.throws_exception(lambda: api.invite.create(a, org_owner, email, entity=file)).code == err.DUPLICATE
     
     assert invite.role == APP_ROLE_READ
     assert invite.invited_user == None
     assert invite.user == org_owner
     assert invite.invited_email == email
     assert invite.object == file
     
     emails = self.get_sent_mails()
     assert len(emails) == 1
     
     assert api.invite.get(invite.eid) == invite
     
     #need to create a new user to accept
     u = fh.create_user(email=email, username=email)
     self.flush()
     
     api.invite.accept(u, u, invite.eid)
     self.flush()
     Session.refresh(invite)
     
     assert invite.invited_user == u
     assert invite.status == STATUS_APPROVED
     
     #invite user in system to proj
     invite = api.invite.create(org_owner, org_owner, email, project=project)
     
     assert invite.invited_user == u
     assert invite.invited_email == email
     assert invite.object == project
     
     emails = self.get_sent_mails()
     assert len(emails) == 2
     
     api.invite.reject(u, u, invite.eid)
     self.flush()
     Session.refresh(invite)
     
     assert invite.invited_user == u
     assert invite.status == STATUS_REJECTED
     
     #invite user in system to org
     invite = api.invite.create(org_owner, org_owner, email, organization=org, role=APP_ROLE_WRITE)
     
     assert invite.object == org
     
     emails = self.get_sent_mails()
     assert len(emails) == 3
     
     # FAIL
     
     #already invited
     assert self.throws_exception(lambda: api.invite.create(a, org_owner, email, entity=file)).code == err.DUPLICATE
     
     #no params
     ex = self.throws_exception(lambda: api.invite.create(org_owner, org_owner, email)).code
     assert ex# == err.NOT_FOUND
     
     #not in org at all
     assert self.throws_exception(lambda: api.invite.create(inviteme, inviteme, email, organization=org)).code == err.FORBIDDEN
     
     #in org as writer
     assert self.throws_exception(lambda: api.invite.create(u, u, email, entity=file)).code == err.FORBIDDEN
     
     #validation
     assert 'email' in self.throws_exception(lambda: api.invite.create(org_owner, org_owner, '', entity=file)).error_dict
     
     
     
Esempio n. 30
0
        Session.add(change_extract)
        extracts.append(change_extract)
        
        indices[e.extract_type] += 1
    
    change.parse_type = parse_info.type
    change.parse_status = parse_info.status
    
    commit()
    return extracts

if __name__ == '__main__':
    """
    accept 2 params:
    eid of the change
    path to file, the raw file (PSD, PDF, whatev...)
    """
    if len(sys.argv) != 4:
        print 'Usage: %s development.ini change_eid /path/to/tmp_file.blah' % sys.argv[0]
        exit(1)
    
    ini, eid, filepath = sys.argv[1:]
    
    load_config(os.path.abspath(ini))
    
    change = Session.query(projects.Change).filter_by(eid=eid).first()
    if not change:
        print 'Cannot find change %s' % eid
        exit(1)
    
    print gen_extracts(change, filepath)
Esempio n. 31
0
class FieldEditor(object):
    """
    The edit functions for a given object are big and tend to be error prone.
    This class allows you to just specify a validator class, the params you want
    to edit, and some functions to edit those params.
    
    This class will handle editing of one variable at a time, it will catch and
    package up multiple errors, and it will do general authorization.
    
    You just extend it and add your edit functions with name edit_<param_name>
    Then you instantiate and call edit(). Example function:
    
    def edit_budget(real_user, user, campaign, key, value):
        raise exceptions.ClientException('OMG bad shit is happening!', field=key)
    
    'key' would be 'budget'
    
    Notes:
    
    * If the user is not an admin and he tries ot edit an admin field, the editor
      will just ignore the field as if he had not specified it.
    * Your editing can work one param at a time.
      so /api/v1/campaign/edit?name=my+name
      /api/v1/campaign/edit?key=name&value=my+name are equivalent
    * Your field editing functions can be passed None
      so /api/v1/campaign/edit?cpc= would unset the CPC.
      If you dont want to accept None, check for it in your edit_ function, not
      in the validator.
    * You must do object ownership authorization outside of this editor. The only
      auth this thing does is an admin check for the editing of admin fields.
      Use the @auth(must_own='asd') on your edit api function.
    * Your edit_ functions can raise ClientExceptions. They will be packaged up in
      a CompoundException and be returned to the client side as a collection.
      If you raise an AdrollException, it will get through to the error middleware.
    """
    def __init__(self, fields, admin_fields, validator):
        self.validator = validator
        self.fields = fields
        self.admin_fields = admin_fields

    def _edit_generic(self, name, obj, key, param, can_be_none=False):
        if not can_be_none and param == None:
            raise exceptions.ClientException('Please enter a %s' % name,
                                             field=key)

        old = getattr(obj, key)
        setattr(obj, key, param)
        self.log(name, key, old, getattr(obj, key))

    def log(self, field, key, old_val, new_val):
        logger.info(
            '%s edited by %s: %s (%s) = %s from %s' %
            (self.object, self.real_user, field, key, new_val, old_val))

    def edit(self, real_user, user, obj, key=None, value=None, **kwargs):

        self.real_user = real_user
        self.user = user
        self.object = obj
        self.params = kwargs

        # for the single field edit
        if key and value != None and key not in kwargs:
            kwargs[key] = value

        # There is no authorization check in here. This is effectively it.
        # If the user is not an admin, the admin fields are stripped out.
        editable_keys = set(real_user.is_admin() and
                            (self.fields + self.admin_fields) or self.fields)

        # is there anything we can edit?
        to_edit = [k for k in kwargs.keys() if k in editable_keys]
        if not to_edit:
            raise ClientException('Specify some parameters to edit, please.',
                                  code=INCOMPLETE)

        # we fill out the kwargs so we dont piss off the validator. hack. poo. Must have all
        # fields as the validator will too.
        for k in self.fields + self.admin_fields:
            if k not in kwargs or k not in editable_keys:
                kwargs[k] = None

        params = validate(self.validator, **kwargs)

        #this is for collecting errors.
        error = CompoundException('Editing issues!', code=FAIL)

        # only go through the keys that we got in the original call/request (to_edit)
        for k in to_edit:
            if k not in editable_keys: continue
            param = params[k]

            fn_name = 'edit_%s' % k
            if hasattr(self, fn_name):

                try:
                    results = getattr(self, fn_name)(real_user, user, obj, k,
                                                     param)
                except ClientException, e:
                    # if error from editing, we will package it up so as to
                    # return all errors at once
                    error.add(e)
            else:
                #this is an adroll exception cause it should bubble up to a WebApp email
                raise AppException('Cannot find %s edit function! :(' %
                                   fn_name,
                                   code=INCOMPLETE)

        if error.has_exceptions:
            raise error

        Session.flush()

        return True
Esempio n. 32
0
    def test_all(self):

        a = fh.create_user(is_admin=True)
        org_owner = fh.create_user()
        inviteme = fh.create_user(email="*****@*****.**")

        org = fh.create_organization(user=org_owner,
                                     subdomain='cats',
                                     name='CATS!')
        project = fh.create_project(user=org_owner,
                                    organization=org,
                                    name=u"helloooo")
        change = project.add_change(org_owner,
                                    u"/main/project/arnold/foobar.gif",
                                    file_path('ffcc00.gif'),
                                    u"this is a new change")
        file = change.entity
        self.flush()

        email = '*****@*****.**'
        #invite user not in the system to file
        invite = api.invite.create(a, org_owner, email, entity=file)

        #based on email only
        assert self.throws_exception(lambda: api.invite.create(
            a, org_owner, email, entity=file)).code == err.DUPLICATE

        assert invite.role == APP_ROLE_READ
        assert invite.invited_user == None
        assert invite.user == org_owner
        assert invite.invited_email == email
        assert invite.object == file

        emails = self.get_sent_mails()
        assert len(emails) == 1

        assert api.invite.get(invite.eid) == invite

        #need to create a new user to accept
        u = fh.create_user(email=email, username=email)
        self.flush()

        api.invite.accept(u, u, invite.eid)
        self.flush()
        Session.refresh(invite)

        assert invite.invited_user == u
        assert invite.status == STATUS_APPROVED

        #invite user in system to proj
        invite = api.invite.create(org_owner,
                                   org_owner,
                                   email,
                                   project=project)

        assert invite.invited_user == u
        assert invite.invited_email == email
        assert invite.object == project

        emails = self.get_sent_mails()
        assert len(emails) == 2

        api.invite.reject(u, u, invite.eid)
        self.flush()
        Session.refresh(invite)

        assert invite.invited_user == u
        assert invite.status == STATUS_REJECTED

        #invite user in system to org
        invite = api.invite.create(org_owner,
                                   org_owner,
                                   email,
                                   organization=org,
                                   role=APP_ROLE_WRITE)

        assert invite.object == org

        emails = self.get_sent_mails()
        assert len(emails) == 3

        # FAIL

        #already invited
        assert self.throws_exception(lambda: api.invite.create(
            a, org_owner, email, entity=file)).code == err.DUPLICATE

        #no params
        ex = self.throws_exception(
            lambda: api.invite.create(org_owner, org_owner, email)).code
        assert ex  # == err.NOT_FOUND

        #not in org at all
        assert self.throws_exception(lambda: api.invite.create(
            inviteme, inviteme, email, organization=org)).code == err.FORBIDDEN

        #in org as writer
        assert self.throws_exception(lambda: api.invite.create(
            u, u, email, entity=file)).code == err.FORBIDDEN

        #validation
        assert 'email' in self.throws_exception(lambda: api.invite.create(
            org_owner, org_owner, '', entity=file)).error_dict