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)
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)
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)
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()
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)
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()
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()
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
def __init__(self, client=None, mappings_version=None): self.es_client = client self.types = (Contact(), Message()) self.mappings_version = mappings_version
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())