Exemple #1
0
    def patch(self):
        """Update a contact with payload.

        method follows the rfc5789 PATCH and rfc7396 Merge patch specifications,
        + 'current_state' caliopen's specs.
        stored messages are modified according to the fields within the payload,
        ie payload fields squash existing db fields, no other modification done.
        If message doesn't existing, response is 404.
        If payload fields are not conform to the message db schema, response is
        422 (Unprocessable Entity).
        Successful response is 204, without a body.
        """
        contact_id = self.request.swagger_data["contact_id"]
        patch = self.request.json

        contact = ContactObject(self.user.user_id, contact_id=contact_id)
        try:
            contact.apply_patch(patch,
                                db=True,
                                index=True,
                                with_validation=True)
        except Exception as exc:
            raise MergePatchError(error=exc)

        return Response(None, 204)
Exemple #2
0
    def delete(self):
        contact_id = self.request.swagger_data["contact_id"]
        contact = ContactObject(self.user.user_id, contact_id=contact_id)

        try:
            contact.delete()
        except Exception as exc:
            if isinstance(exc, ForbiddenAction):
                raise HTTPForbidden(exc)
            else:
                raise HTTPServerError(exc)

        return Response(None, 204)
Exemple #3
0
    def delete(self):
        contact_id = self.request.swagger_data["contact_id"]
        contact = ContactObject(user=self.user, contact_id=contact_id)

        try:
            contact.delete()
        except Exception as exc:
            if isinstance(exc, ForbiddenAction):
                raise HTTPForbidden(exc)
            else:
                raise HTTPServerError(exc)

        return Response(None, 204)
Exemple #4
0
def copy_user_contacts(user,
                       new_domain,
                       old_domain,
                       only_index=False,
                       filter_id=None):
    ids = copy_contacts(user, only_index, filter_id)
    for id in ids:
        contact = ContactObject(user, contact_id=id)
        try:
            contact.get_db()
        except NotFound:
            log.error('Contact {} not found for user {}'.format(
                user.contact_id, user.user_id))
            continue
        contact.unmarshall_db()

        if not only_index:
            if str(user.contact_id) == str(id):
                try:
                    patch_user_contact(user, contact, new_domain, old_domain)
                except Exception as exc:
                    log.exception('Error during user contact patch {}'.format(
                        user.user_id))
                continue
            for email in contact.emails:
                ContactLookup.create(user=user,
                                     contact_id=id,
                                     value=email.address.lower(),
                                     type='email')
            for ident in contact.identities:
                ContactLookup.create(user=user,
                                     contact_id=id,
                                     value=ident.name.lower(),
                                     type=ident.type.lower())
        contact.create_index()
Exemple #5
0
    def patch(self):
        """Update a contact with payload.

        method follows the rfc5789 PATCH and rfc7396 Merge
        patch specifications, + 'current_state' caliopen's specs.
        stored messages are modified according to the fields within
        the payload, ie payload fields squash existing db fields,
        no other modification done.
        If message doesn't existing, response is 404.
        If payload fields are not conform to the message db schema, response is
        422 (Unprocessable Entity).
        Successful response is 204, without a body.
        """
        contact_id = self.request.swagger_data["contact_id"]
        patch = self.request.json

        contact = ContactObject(user=self.user, contact_id=contact_id)
        try:
            contact.apply_patch(patch, db=True, index=True,
                                with_validation=True)
        except Exception as exc:
            raise MergePatchError(error=exc)

        return Response(None, 204)
Exemple #6
0
    def get(self):
        contact_id = self.request.swagger_data["contact_id"]
        try:
            uuid.UUID(contact_id)
        except Exception as exc:
            log.error("unable to extract contact_id: {}".format(exc))
            raise ValidationError(exc)

        contact = ContactObject(self.user.user_id, contact_id=contact_id)
        contact.get_db()
        contact.unmarshall_db()
        return contact.marshall_json_dict()
Exemple #7
0
    def get(self):
        contact_id = self.request.swagger_data["contact_id"]
        try:
            uuid.UUID(contact_id)
        except Exception as exc:
            log.error("unable to extract contact_id: {}".format(exc))
            raise ValidationError(exc)

        contact = ContactObject(user=self.user, contact_id=contact_id)
        try:
            contact.get_db()
            contact.unmarshall_db()
        except Exception as exc:
            log.warn(exc)
            raise ResourceNotFound(detail=exc.message)
        return contact.marshall_json_dict()
Exemple #8
0
    def create(cls, new_user):
        """Create a new user.

        @param: new_user is a parameters/user.py.NewUser object
        # 1.check username regex
        # 2.check username is not in reserved_name table
        # 3.check recovery email validity (TODO : check if email is not within
        #   the current Caliopen's instance)
        # 4.check username availability
        # 5.add username to user cassa user_name table (to block the
        #   availability)
        # 6.check password strength (and regex?)
        # then
        #      create user and linked contact
        """

        def rollback_username_storage(username):
            UserName.get(username).delete()

        # 0. check for user email white list and max number of users
        cls._check_whitelistes(new_user)
        cls._check_max_users()

        # 1.
        try:
            validators.is_valid_username(new_user.name)
        except SyntaxError:
            raise ValueError("Malformed username")

        # 2.
        try:
            ReservedName.get(new_user.name)
            raise ValueError('Reserved user name')
        except NotFound:
            pass

        user_id = uuid.uuid4()
        # 3.
        if not new_user.recovery_email:
            raise ValueError("Missing recovery email")

        try:
            cls.validate_recovery_email(new_user.recovery_email)
        except Exception as exc:
            log.info("recovery email failed validation : {}".format(exc))
            raise ValueError(exc)

        # 4. & 5.
        if User.is_username_available(new_user.name.lower()):
            # save username immediately to prevent concurrent creation
            UserName.create(name=new_user.name.lower(), user_id=user_id)
            # NB : need to rollback this username creation if the below
            #      User creation failed for any reason
        else:
            raise ValueError("Username already exist")

        # 6.
        try:
            user_inputs = [new_user.name.encode("utf-8"),
                           new_user.recovery_email.encode("utf-8")]
            # TODO: add contact inputs if any
            password_strength = zxcvbn(new_user.password,
                                       user_inputs=user_inputs)
            privacy_features = {"password_strength":
                                    str(password_strength["score"])}
            passwd = new_user.password.encode('utf-8')
            new_user.password = bcrypt.hashpw(passwd, bcrypt.gensalt())
        except Exception as exc:
            log.exception(exc)
            rollback_username_storage(new_user.name)
            raise exc

        try:
            new_user.validate()  # schematic model validation
        except Exception as exc:
            rollback_username_storage(new_user.name)
            log.info("schematics validation error: {}".format(exc))
            raise ValueError("new user malformed")

        try:
            recovery = new_user.recovery_email
            if hasattr(new_user, "contact"):
                family_name = new_user.contact.family_name
                given_name = new_user.contact.given_name
            else:
                family_name = ""
                given_name = ""

            # XXX PI compute
            pi = PIModel()
            pi.technic = 0
            pi.comportment = 0
            pi.context = 0
            pi.version = 0
            shard_id = allocate_user_shard(user_id)

            core = super(User, cls).create(user_id=user_id,
                                           name=new_user.name,
                                           password=new_user.password,
                                           recovery_email=recovery,
                                           params=new_user.params,
                                           date_insert=datetime.datetime.now(
                                               tz=pytz.utc),
                                           privacy_features=privacy_features,
                                           pi=pi,
                                           family_name=family_name,
                                           given_name=given_name,
                                           shard_id=shard_id)
        except Exception as exc:
            log.info(exc)
            rollback_username_storage(new_user.name)
            raise exc

        # **** operations below do not raise fatal error and rollback **** #
        # Setup index
        setup_index(core)
        # Setup others entities related to user
        setup_system_tags(core)
        setup_settings(core, new_user.settings)

        UserRecoveryEmail.create(recovery_email=recovery, user_id=user_id)
        # Add a default local identity on a default configured domain
        default_domain = Configuration('global').get('default_domain')
        default_local_id = '{}@{}'.format(core.name, default_domain)
        if not core.add_local_identity(default_local_id):
            log.warn('Impossible to create default local identity {}'.
                     format(default_local_id))

        # save and index linked contact
        if hasattr(new_user, "contact"):
            contact = Contact(user=core, **new_user.contact.serialize())
            contact.contact_id = uuid.uuid4()
            contact.title = Contact._compute_title(contact)

            for email in contact.emails:
                if email.address is not None and validate_email(email.address):
                    email.email_id = uuid.uuid4()

            try:
                contact.marshall_db()
                contact.save_db()
            except Exception as exc:
                log.info("save_db error : {}".format(exc))

            contact.marshall_index()
            contact.save_index()
            # XXX should use core proxy, not directly model attribute
            core.model.contact_id = contact.contact_id

            # fill contact_lookup table
            log.info("contact id : {}".format(contact.contact_id))
            # TOFIX does not work
            # ContactLookup.create(user_id=core.user_id,
            #                     value=default_local_id, type='email',
            #                     contact_ids=[contact.contact_id])

        core.save()

        return core
Exemple #9
0
 def __init__(self, client=None, mappings_version=None):
     self.es_client = client
     self.types = (Contact(), Message())
     self.mappings_version = mappings_version
Exemple #10
0
    def create(cls, new_user):
        """Create a new user.

        @param: new_user is a parameters/user.py.NewUser object
        # 1.check username regex
        # 2.check username is not in reserved_name table
        # 3.check recovery email validity (TODO : check if email is not within
        #   the current Caliopen's instance)
        # 4.check username availability
        # 5.add username to user cassa user_name table (to block the
        #   availability)
        # 6.check password strength (and regex?)
        # then
        #      create user and linked contact
        """
        def rollback_username_storage(username):
            UserName.get(username).delete()

        # 0. check for user email white list and max number of users
        cls._check_whitelistes(new_user)
        cls._check_max_users()

        # 1.
        try:
            validators.is_valid_username(new_user.name)
        except SyntaxError:
            raise ValueError("Malformed username")

        # 2.
        try:
            ReservedName.get(new_user.name)
            raise ValueError('Reserved user name')
        except NotFound:
            pass

        user_id = uuid.uuid4()
        # 3.
        if not new_user.recovery_email:
            raise ValueError("Missing recovery email")

        try:
            cls.validate_recovery_email(new_user.recovery_email)
        except Exception as exc:
            log.info("recovery email failed validation : {}".format(exc))
            raise ValueError(exc)

        # 4. & 5.
        if User.is_username_available(new_user.name.lower()):
            # save username immediately to prevent concurrent creation
            UserName.create(name=new_user.name.lower(), user_id=user_id)
            # NB : need to rollback this username creation if the below
            #      User creation failed for any reason
        else:
            raise ValueError("Username already exist")

        # 6.
        try:
            user_inputs = [
                new_user.name.encode("utf-8"),
                new_user.recovery_email.encode("utf-8")
            ]
            # TODO: add contact inputs if any
            password_strength = zxcvbn(new_user.password,
                                       user_inputs=user_inputs)
            privacy_features = {
                "password_strength": str(password_strength["score"])
            }
            passwd = new_user.password.encode('utf-8')
            new_user.password = bcrypt.hashpw(passwd, bcrypt.gensalt())
        except Exception as exc:
            log.exception(exc)
            rollback_username_storage(new_user.name)
            raise exc

        try:
            new_user.validate()  # schematic model validation
        except Exception as exc:
            rollback_username_storage(new_user.name)
            log.info("schematics validation error: {}".format(exc))
            raise ValueError("new user malformed")

        try:
            recovery = new_user.recovery_email
            if hasattr(new_user, "contact"):
                family_name = new_user.contact.family_name
                given_name = new_user.contact.given_name
            else:
                family_name = ""
                given_name = ""

            # XXX PI compute
            pi = PIModel()
            pi.technic = 0
            pi.comportment = 0
            pi.context = 0
            pi.version = 0

            core = super(User, cls).create(
                user_id=user_id,
                name=new_user.name,
                password=new_user.password,
                recovery_email=recovery,
                params=new_user.params,
                date_insert=datetime.datetime.now(tz=pytz.utc),
                privacy_features=privacy_features,
                pi=pi,
                family_name=family_name,
                given_name=given_name)
        except Exception as exc:
            log.info(exc)
            rollback_username_storage(new_user.name)
            raise exc

        # **** operations below do not raise fatal error and rollback **** #
        # Setup index
        setup_index(core)
        # Setup others entities related to user
        setup_system_tags(core)
        setup_settings(core, new_user.settings)

        UserRecoveryEmail.create(recovery_email=recovery, user_id=user_id)
        # Add a default local identity on a default configured domain
        default_domain = Configuration('global').get('default_domain')
        default_local_id = '{}@{}'.format(core.name, default_domain)
        if not core.add_local_identity(default_local_id):
            log.warn('Impossible to create default local identity {}'.format(
                default_local_id))

        # save and index linked contact
        if hasattr(new_user, "contact"):
            contact = Contact(user_id=user_id, **new_user.contact.serialize())
            contact.contact_id = uuid.uuid4()
            contact.title = Contact._compute_title(contact)

            for email in contact.emails:
                if email.address is not None and validate_email(email.address):
                    email.email_id = uuid.uuid4()

            try:
                contact.marshall_db()
                contact.save_db()
            except Exception as exc:
                log.info("save_db error : {}".format(exc))

            contact.marshall_index()
            contact.save_index()
            # XXX should use core proxy, not directly model attribute
            core.model.contact_id = contact.contact_id

            # fill contact_lookup table
            log.info("contact id : {}".format(contact.contact_id))
            # TOFIX does not work
            # ContactLookup.create(user_id=core.user_id,
            #                     value=default_local_id, type='email',
            #                     contact_ids=[contact.contact_id])

        core.save()

        return core
 def __init__(self, es_client):
     self.es_client = es_client
     self.types = (Contact(), Message())