def start_session(cls): ''' POST: Start chat session with another user. :args user: User Id of nereid user. :return: JSON as { thread_id: uuid, members: Serialized members list. } ''' NereidUser = Pool().get('nereid.user') form = NewChatForm() if not form.validate_on_submit(): return jsonify(errors=form.errors), 400 chat_with = NereidUser(form.user.data) if not request.nereid_user.can_chat(chat_with): abort(403, "You can only talk to friends") chat = cls.get_or_create_room( request.nereid_user.id, chat_with.id ) return jsonify({ 'thread_id': chat.thread, 'members': map( lambda m: m.user.serialize(), chat.members ) })
def new_post(cls): """Create a new post """ post_form = BlogPostForm(request.form) if request.method == 'POST' and post_form.validate(): post, = cls.create([{ 'title': post_form.title.data, 'uri': post_form.uri.data, 'content': post_form.content.data, 'nereid_user': request.nereid_user.id, 'allow_guest_comments': post_form.allow_guest_comments.data, }]) if post_form.publish.data: cls.publish([post]) flash('Your post has been published.') else: flash('Your post has been saved.') if request.is_xhr: return jsonify(success=True, item=post.serialize()) return redirect(url_for( 'blog.post.render', user_id=post.nereid_user.id, uri=post.uri )) if request.is_xhr: return jsonify( success=request.method != 'POST', # False for POST, else True errors=post_form.errors or None, ) return render_template('blog_post_form.jinja', form=post_form)
def add(cls): """ Adds a contact mechanism to the party's contact mechanisms """ form = cls.get_form() if form.validate_on_submit(): cls.create( [ { "party": request.nereid_user.party.id, "type": form.type.data, "value": form.value.data, "comment": form.comment.data, } ] ) if request.is_xhr: return jsonify({"success": True}) return redirect(request.referrer) if request.is_xhr: return jsonify({"success": False}) else: for field, messages in form.errors: flash("<br>".join(messages), "Field %s" % field) return redirect(request.referrer)
def cms_static_upload(cls, upload_type): """ Upload the file for cms """ StaticFile = Pool().get("nereid.static.file") file = request.files['file'] if file: static_file, = StaticFile.create([{ 'folder': current_website.cms_static_folder, 'name': '_'.join([ str(int(time.time())), secure_filename(file.filename), ]), 'type': upload_type, 'file_binary': file.read(), }]) if request.is_xhr: return jsonify(success=True, item=static_file.serialize()) flash("File uploaded") if request.is_xhr: return jsonify(success=False) return redirect(request.referrer)
def start_session(cls): ''' POST: Start chat session with another user. :args user: User Id of nereid user. :return: JSON as { thread_id: uuid, members: Serialized members list. } ''' NereidUser = Pool().get('nereid.user') form = NewChatForm() if not form.validate_on_submit(): return jsonify(errors=form.errors), 400 chat_with = NereidUser(form.user.data) if not request.nereid_user.can_chat(chat_with): abort(403, "You can only talk to friends") chat = cls.get_or_create_room(request.nereid_user.id, chat_with.id) return jsonify({ 'thread_id': chat.thread, 'members': map(lambda m: m.user.serialize(), chat.members) })
def render_comments(self): """ Render comments GET: Return json of all the comments of this post. POST: Create new comment for this post. """ if self.state != 'Published': abort(404) # Add re_captcha if the configuration has such an option and user # is guest if 're_captcha_public' in CONFIG.options and request.is_guest_user: comment_form = GuestCommentForm( request.form, captcha={'ip_address': request.remote_addr} ) else: comment_form = PostCommentForm(request.form) if request.method == 'GET': if self.nereid_user == request.nereid_user: return jsonify(comments=[ comment.serialize() for comment in self.comments ]) return jsonify(comments=[ comment.serialize() for comment in self.comments if not comment.is_spam ]) # If post does not allow guest comments, # then dont allow guest user to comment if not self.allow_guest_comments and request.is_guest_user: flash('Guests are not allowed to write comments') if request.is_xhr: return jsonify( success=False, errors=['Guests are not allowed to write comments'] ) return redirect(url_for( 'blog.post.render', user_id=self.nereid_user.id, uri=self.uri )) if request.method == 'POST' and comment_form.validate(): self.write([self], { 'comments': [('create', [{ 'nereid_user': current_user.id if not current_user.is_anonymous() else None, 'name': current_user.display_name if not current_user.is_anonymous() else comment_form.name.data, 'content': comment_form.content.data, }])] }) if request.is_xhr: return jsonify(success=True) if comment_form.validate() \ else jsonify(success=False, errors=comment_form.errors) return redirect(url_for( 'blog.post.render', user_id=self.nereid_user.id, uri=self.uri ))
def edit_post(self): """ Edit an existing post """ if self.nereid_user != request.nereid_user: abort(404) # Search for a post with same uri post_form = BlogPostForm(request.form, obj=self) with Transaction().set_context(blog_id=self.id): if request.method == 'POST' and post_form.validate(): self.title = post_form.title.data self.content = post_form.content.data self.allow_guest_comments = post_form.allow_guest_comments.data self.save() flash('Your post has been updated.') if request.is_xhr: return jsonify(success=True, item=self.serialize()) return redirect( url_for('blog.post.render', user_id=self.nereid_user.id, uri=self.uri)) if request.is_xhr: return jsonify( success=request.method != 'POST', # False for POST, else True errors=post_form.errors or None, ) return render_template('blog_post_edit.jinja', form=post_form, post=self)
def edit_post(self): """ Edit an existing post """ if self.nereid_user != request.nereid_user: abort(404) # Search for a post with same uri post_form = BlogPostForm(request.form, obj=self) with Transaction().set_context(blog_id=self.id): if request.method == 'POST' and post_form.validate(): self.title = post_form.title.data self.content = post_form.content.data self.allow_guest_comments = post_form.allow_guest_comments.data self.save() flash('Your post has been updated.') if request.is_xhr: return jsonify(success=True, item=self.serialize()) return redirect(url_for( 'blog.post.render', user_id=self.nereid_user.id, uri=self.uri )) if request.is_xhr: return jsonify( success=request.method != 'POST', # False for POST, else True errors=post_form.errors or None, ) return render_template( 'blog_post_edit.jinja', form=post_form, post=self )
def registration(cls): """ Invokes registration of an user """ Party = Pool().get('party.party') ContactMechanism = Pool().get('party.contact_mechanism') registration_form = cls.get_registration_form() if registration_form.validate_on_submit(): with Transaction().set_context(active_test=False): existing = cls.search([ ('email', '=', registration_form.email.data.lower()), ('company', '=', current_website.company.id), ]) if existing: message = _('A registration already exists with this email. ' 'Please contact customer care') if request.is_xhr or request.is_json: return jsonify(message=unicode(message)), 400 else: flash(message) else: party = Party(name=registration_form.name.data) party.addresses = [] party.contact_mechanisms = [ ContactMechanism(type="email", value=registration_form.email.data) ] party.save() nereid_user = cls( **{ 'party': party.id, 'display_name': registration_form.name.data, 'email': registration_form.email.data, 'password': registration_form.password.data, 'company': current_website.company.id, }) nereid_user.save() registration.send(nereid_user) nereid_user.send_activation_email() message = _( 'Registration Complete. Check your email for activation') if request.is_xhr or request.is_json: return jsonify(message=unicode(message)), 201 else: flash(message) return redirect( request.args.get('next', url_for('nereid.website.home'))) if registration_form.errors and (request.is_xhr or request.is_json): return jsonify({ 'message': unicode(_('Form has errors')), 'errors': registration_form.errors, }), 400 return render_template('registration.jinja', form=registration_form)
def add_to_cart(cls): """ Adds the given item to the cart if it exists or to a new cart The form is expected to have the following data is post quantity : decimal product : integer ID action : set (default), add Response: 'OK' if X-HTTPRequest Redirect to shopping cart if normal request """ Product = Pool().get('product.product') form = AddtoCartForm() if form.validate_on_submit(): cart = cls.open_cart(create_order=True) action = request.values.get('action', 'set') if form.quantity.data <= 0: message = _( 'Be sensible! You can only add real quantities to cart') if request.is_xhr: return jsonify(message=unicode(message)), 400 flash(message) return redirect(url_for('nereid.cart.view_cart')) if not Product(form.product.data).template.salable: message = _("This product is not for sale") if request.is_xhr: return jsonify(message=unicode(message)), 400 flash(message) return redirect(request.referrer) sale_line = cart.sale._add_or_update( form.product.data, form.quantity.data, action ) # Validate that product availability in inventory is not less than # warehouse quantity sale_line.validate_for_product_inventory() sale_line.save() if action == 'add': message = _('The product has been added to your cart') else: message = _('Your cart has been updated with the product') if request.is_xhr: return jsonify( message=unicode(message), line=sale_line.serialize(purpose='cart') ), 200 flash(message, 'info') return redirect(url_for('nereid.cart.view_cart'))
def registration(cls): """ Invokes registration of an user """ Party = Pool().get('party.party') registration_form = cls.get_registration_form() if registration_form.validate_on_submit(): with Transaction().set_context(active_test=False): existing = cls.search([ ('email', '=', registration_form.email.data), ('company', '=', request.nereid_website.company.id), ]) if existing: message = _( 'A registration already exists with this email. ' 'Please contact customer care' ) if request.is_xhr or request.is_json: return jsonify(message=unicode(message)), 400 else: flash(message) else: party = Party(name=registration_form.name.data) party.addresses = [] party.save() nereid_user = cls(**{ 'party': party.id, 'display_name': registration_form.name.data, 'email': registration_form.email.data, 'password': registration_form.password.data, 'company': request.nereid_website.company.id, } ) nereid_user.save() registration.send(nereid_user) nereid_user.send_activation_email() message = _( 'Registration Complete. Check your email for activation' ) if request.is_xhr or request.is_json: return jsonify(message=unicode(message)), 201 else: flash(message) return redirect( request.args.get('next', url_for('nereid.website.home')) ) if registration_form.errors and (request.is_xhr or request.is_json): return jsonify({ 'message': unicode(_('Form has errors')), 'errors': registration_form.errors, }), 400 return render_template('registration.jinja', form=registration_form)
def add_to_cart(cls): """ Adds the given item to the cart if it exists or to a new cart The form is expected to have the following data is post quantity : decimal product : integer ID action : set (default), add Response: 'OK' if X-HTTPRequest Redirect to shopping cart if normal request """ Product = Pool().get('product.product') form = AddtoCartForm() if form.validate_on_submit(): cart = cls.open_cart(create_order=True) action = request.values.get('action', 'set') if form.quantity.data <= 0: message = _( 'Be sensible! You can only add real quantities to cart') if request.is_xhr: return jsonify(message=unicode(message)), 400 flash(message) return redirect(url_for('nereid.cart.view_cart')) if not Product(form.product.data).salable: message = _("This product is not for sale") if request.is_xhr: return jsonify(message=unicode(message)), 400 flash(message) return redirect(request.referrer) sale_line = cart.sale._add_or_update(form.product.data, form.quantity.data, action) # Validate that product availability in inventory is not less than # warehouse quantity sale_line.validate_for_product_inventory() sale_line.save() cart_updated.send(cart) if action == 'add': message = _('The product has been added to your cart') else: message = _('Your cart has been updated with the product') if request.is_xhr: return jsonify(message=unicode(message), line=sale_line.serialize(purpose='cart')), 200 flash(message, 'info') return redirect(url_for('nereid.cart.view_cart'))
def login(cls): """ Simple login based on the email and password Required post data see :class:LoginForm """ login_form = LoginForm(request.form) if not request.is_guest_user and request.args.get('next'): return redirect(request.args['next']) if request.method == 'POST' and login_form.validate(): NereidUser = Pool().get('nereid.user') user = NereidUser.authenticate( login_form.email.data, login_form.password.data ) # Result can be the following: # 1 - Browse record of User (successful login) # 2 - None - Login failure without message # 3 - Any other false value (no message is shown. useful if you # want to handle the message shown to user) if user: # NOTE: Translators leave %s as such flash(_("You are now logged in. Welcome %(name)s", name=user.display_name)) if login_user(user, remember=login_form.remember.data): if request.is_xhr: return jsonify({ 'success': True, 'user': user.serialize(), }) else: return redirect( request.values.get( 'next', url_for('nereid.website.home') ) ) else: flash(_("Your account has not been activated yet!")) elif user is None: flash(_("Invalid login credentials")) failed_login.send(form=login_form) if request.is_xhr: rv = jsonify(message="Bad credentials") rv.status_code = 401 return rv return render_template('login.jinja', login_form=login_form)
def login(cls): """ Simple login based on the email and password Required post data see :class:LoginForm """ login_form = LoginForm(request.form) if not current_user.is_anonymous() and request.args.get('next'): return redirect(request.args['next']) if request.method == 'POST' and login_form.validate(): NereidUser = Pool().get('nereid.user') user = NereidUser.authenticate( login_form.email.data, login_form.password.data ) # Result can be the following: # 1 - Browse record of User (successful login) # 2 - None - Login failure without message # 3 - Any other false value (no message is shown. useful if you # want to handle the message shown to user) if user: # NOTE: Translators leave %s as such flash(_("You are now logged in. Welcome %(name)s", name=user.display_name)) if login_user(user, remember=login_form.remember.data): if request.is_xhr: return jsonify({ 'success': True, 'user': user.serialize(), }) else: return redirect( request.values.get( 'next', url_for('nereid.website.home') ) ) else: flash(_("Your account has not been activated yet!")) elif user is None: flash(_("Invalid login credentials")) failed_login.send(form=login_form) if request.is_xhr: rv = jsonify(message="Bad credentials") rv.status_code = 401 return rv return render_template('login.jinja', login_form=login_form)
def registration(cls): """ Invokes registration of an user """ Party = Pool().get("party.party") ContactMechanism = Pool().get("party.contact_mechanism") registration_form = cls.get_registration_form() if registration_form.validate_on_submit(): with Transaction().set_context(active_test=False): existing = cls.search( [("email", "=", registration_form.email.data.lower()), ("company", "=", current_website.company.id)] ) if existing: message = _("A registration already exists with this email. " "Please contact customer care") if request.is_xhr or request.is_json: return jsonify(message=unicode(message)), 400 else: flash(message) else: party = Party(name=registration_form.name.data) party.addresses = [] party.contact_mechanisms = [ContactMechanism(type="email", value=registration_form.email.data)] party.save() nereid_user = cls( **{ "party": party.id, "display_name": registration_form.name.data, "email": registration_form.email.data, "password": registration_form.password.data, "company": current_website.company.id, } ) nereid_user.save() registration.send(nereid_user) nereid_user.send_activation_email() message = _("Registration Complete. Check your email for activation") if request.is_xhr or request.is_json: return jsonify(message=unicode(message)), 201 else: flash(message) return redirect(request.args.get("next", url_for("nereid.website.home"))) if registration_form.errors and (request.is_xhr or request.is_json): return jsonify({"message": unicode(_("Form has errors")), "errors": registration_form.errors}), 400 return render_template("registration.jinja", form=registration_form)
def availability(cls, uri): """ Returns the following information for a product: +-------------------+-----------------------------------------------+ | quantity | Available readily to buy | +-------------------+-----------------------------------------------+ | forecast_quantity | Forecasted quantity, if the site needs it | +-------------------+-----------------------------------------------+ .. note:: To modify the availability, or to send any additional information, it is recommended to subclass the :py:meth:`~get_availability` and implement your custom logic. For example, you might want to check stock with your vendor for back orders or send a message like `Only 5 pieces left` :param uri: URI of the product for which the availability needs to be found :return: JSON object """ try: product, = cls.search([ ('displayed_on_eshop', '=', True), ('uri', '=', uri), ]) except ValueError: return abort(404) return jsonify(product.get_availability())
def add_to_cart(cls): """ Adds the given item to the cart if it exists or to a new cart The form is expected to have the following data is post quantity : decimal product : integer ID action : set (default), add Response: 'OK' if X-HTTPRequest Redirect to shopping cart if normal request """ form = AddtoCartForm() if form.validate_on_submit(): cart = cls.open_cart(create_order=True) action = request.values.get('action', 'set') if form.quantity.data <= 0: flash( _('Be sensible! You can only add real quantities to cart')) return redirect(url_for('nereid.cart.view_cart')) cart._add_or_update(form.product.data, form.quantity.data, action) if action == 'add': flash(_('The product has been added to your cart'), 'info') else: flash(_('Your cart has been updated with the product'), 'info') if request.is_xhr: return jsonify(message='OK') return redirect(url_for('nereid.cart.view_cart'))
def get_all_countries(cls): """ Returns serialized list of all countries """ return jsonify(countries=[ country.serialize() for country in cls.search([]) ])
def search_auto_complete(cls): """ Handler for auto-completing search. """ return jsonify(results=cls.auto_complete( request.args.get('q', '') ))
def delete_task(cls, task_id): """ Delete the task from project Tasks can be deleted only if 1. The user is project admin 2. The user is an admin member in the project :param task_id: Id of the task to be deleted """ task = cls.get_task(task_id) # Check if user is among the project admins if not request.nereid_user.is_admin_of_project(task.parent): flash("Sorry! You are not allowed to delete tasks. \ Contact your project admin for the same.") return redirect(request.referrer) cls.write([task], {'active': False}) if request.is_xhr: return jsonify({ 'success': True, }) flash("The task has been deleted") return redirect( url_for('project.work.render_project', project_id=task.parent.id))
def render(cls, user_id, uri): "Render the blog post" NereidUser = Pool().get('nereid.user') if 're_captcha_public' in CONFIG.options and request.is_guest_user: comment_form = GuestCommentForm( captcha={'ip_address': request.remote_addr}) else: comment_form = PostCommentForm() user = NereidUser(user_id) posts = cls.search([ ('nereid_user', '=', user.id), ('uri', '=', uri), ]) if not posts: abort(404) # if only one post is found then it is rendered and # if more than one are found then the first one is rendered post = posts[0] if not (post.state == 'Published' or request.nereid_user == post.nereid_user): abort(403) if request.is_xhr: return jsonify(post.serialize()) return render_template('blog_post.jinja', post=post, comment_form=comment_form, poster=user)
def change_password(cls): """ Changes the password .. tip:: On changing the password, the user is logged out and the login page is thrown at the user """ form = ChangePasswordForm() if request.method == 'POST' and form.validate(): if current_user.match_password(form.old_password.data): cls.write([current_user], {'password': form.password.data}) logout_user() return cls.build_response( 'Your password has been successfully changed! ' 'Please login again', redirect(url_for('nereid.website.login')), 200) else: return cls.build_response( 'The current password you entered is invalid', render_template('change-password.jinja', change_password_form=form), 400) if form.errors and (request.is_xhr or request.is_json): return jsonify(errors=form.errors), 400 return render_template('change-password.jinja', change_password_form=form)
def get_passes(cls, device, pass_type=None, version=None): """ Getting the Serial Numbers for Passes Associated with the Device """ domain = [ ('device_library_identifier', '=', device), ('pass_.active', '=', True), ] updated_since = request.args.get('passesUpdatedSince', type=dateutil.parser.parse) passes = set() for registration in cls.search(domain): if updated_since is not None and \ registration.pass_.last_update < updated_since: # If updated_since is specified and the last_update of the # pass is before it, there is nothing more to send continue passes.add(registration.pass_) if not passes: return '', 204 rv = defaultdict(list) for pass_ in passes: rv[pass_.last_update.isoformat(' ')].append(str(pass_.id)) return jsonify(rv), 200
def get_available_gateways(cls): """Return the JSONified list of payment gateways available This is a XHR only method If type is specified as address then an address lookup is done """ Address = Pool().get('party.address') value = request.args.get('value', 0, type=int) if request.values.get('type') == 'address': # Address lookup only when logged in if request.is_guest_user: abort(403) # If not validated as user's address this could lead to # exploitation by ID if value not in [a.id for a in request.nereid_user.party.addresses]: abort(403) address = Address(value) value = address.country.id rv = [{ 'id': g.id, 'name': g.name, 'image': g.get_image(), } for g in cls._get_available_gateways(value)] return jsonify(result=rv)
def edit_task(self): """ Edit the task """ Activity = Pool().get('nereid.activity') Work = Pool().get('timesheet.work') task = self.get_task(self.id) Work.write([task.work], { 'name': request.form.get('name'), }) self.write([task], { 'comment': request.form.get('comment') }) Activity.create([{ 'actor': request.nereid_user.id, 'object_': 'project.work, %d' % task.id, 'verb': 'edited_task', 'target': 'project.work, %d' % task.parent.id, 'project': task.parent.id, }]) if request.is_xhr: return jsonify({ 'success': True, 'name': self.rec_name, 'comment': self.comment, }) return redirect(request.referrer)
def get_available_gateways(cls): """Return the JSONified list of payment gateways available This is a XHR only method If type is specified as address then an address lookup is done """ Address = Pool().get('party.address') value = request.args.get('value', 0, type=int) if request.values.get('type') == 'address': # Address lookup only when logged in if request.is_guest_user: abort(403) # If not validated as user's address this could lead to # exploitation by ID if value not in [ a.id for a in request.nereid_user.party.addresses ]: abort(403) address = Address(value) value = address.country.id rv = [{ 'id': g.id, 'name': g.name, 'image': g.get_image(), } for g in cls._get_available_gateways(value)] return jsonify(result=rv)
def add_to_cart(cls): """ Adds the given item to the cart if it exists or to a new cart The form is expected to have the following data is post quantity : decimal product : integer ID action : set (default), add Response: 'OK' if X-HTTPRequest Redirect to shopping cart if normal request """ form = AddtoCartForm() if form.validate_on_submit(): cart = cls.open_cart(create_order=True) action = request.values.get('action', 'set') if form.quantity.data <= 0: flash( _('Be sensible! You can only add real quantities to cart') ) return redirect(url_for('nereid.cart.view_cart')) cart._add_or_update( form.product.data, form.quantity.data, action ) if action == 'add': flash(_('The product has been added to your cart'), 'info') else: flash(_('Your cart has been updated with the product'), 'info') if request.is_xhr: return jsonify(message='OK') return redirect(url_for('nereid.cart.view_cart'))
def assign_task(self, task_id): """Assign task to a user :param task_id: Id of Task """ nereid_user_obj = Pool().get('nereid.user') task = self.get_task(task_id) new_assignee = nereid_user_obj.browse(int(request.form['user'])) if self.can_write(task.parent, new_assignee): self.write(task.id, { 'assigned_to': new_assignee.id }) if request.is_xhr: return jsonify({ 'success': True, }) flash("Task assigned to %s" % new_assignee.name) return redirect(request.referrer) flash("Only employees can be assigned to tasks.") return redirect(request.referrer)
def render(cls, user_id, uri): "Render the blog post" NereidUser = Pool().get('nereid.user') if 're_captcha_public' in CONFIG.options and request.is_guest_user: comment_form = GuestCommentForm( captcha={'ip_address': request.remote_addr} ) else: comment_form = PostCommentForm() user = NereidUser(user_id) posts = cls.search([ ('nereid_user', '=', user.id), ('uri', '=', uri), ]) if not posts: abort(404) # if only one post is found then it is rendered and # if more than one are found then the first one is rendered post = posts[0] if not (post.state == 'Published' or request.nereid_user == post.nereid_user): abort(403) if request.is_xhr: return jsonify(post.serialize()) return render_template( 'blog_post.jinja', post=post, comment_form=comment_form, poster=user )
def update_comment(self, task_id, comment_id): """ Update a specific comment. """ project_obj = Pool().get('project.work') nereid_user_obj = Pool().get('nereid.user') # allow modification only if the user is an admin or the author of # this ticket task = project_obj.browse(task_id) comment = self.browse(comment_id) assert task.type == "task" assert comment.project.id == task.id # Allow only admins and author of this comment to edit it if nereid_user_obj.is_project_admin(request.nereid_user) or \ comment.updated_by == request.nereid_user: self.write(comment_id, {'comment': request.form['comment']}) else: abort(403) if request.is_xhr: comment_record = self.browse(comment_id) html = render_template('comment.jinja', comment=comment_record) return jsonify({ 'success': True, 'html': html, 'state': project_obj.browse(task.id).state, }) return redirect(request.referrer)
def render_task(cls, task_id, project_id): """ Renders the task in a project """ task = cls.get_task(task_id) comments = sorted(task.history + task.work.timesheet_lines + task.attachments + task.repo_commits, key=lambda x: x.create_date) hours = {} for line in task.work.timesheet_lines: hours[line.employee] = hours.setdefault(line.employee, 0) + \ line.hours if request.is_xhr: response = cls.serialize(task) with Transaction().set_context(task=task_id): response['comments'] = [ comment.serialize('listing') for comment in comments ] return jsonify(response) return render_template('project/task.jinja', task=task, active_type_name='render_task_list', project=task.parent, comments=comments, timesheet_summary=hours)
def reset_account(cls): """ Reset the password for the user. .. tip:: This does NOT reset the password, but just creates an activation code and sends the link to the email of the user. If the user uses the link, he can change his password. """ form = ResetAccountForm() if form.validate_on_submit(): try: nereid_user, = cls.search([ ('email', '=', form.email.data), ('company', '=', current_website.company.id), ]) except ValueError: return cls.build_response( 'Invalid email address', render_template('reset-password.jinja'), 400 ) nereid_user.send_reset_email() return cls.build_response( 'An email has been sent to your account for resetting' ' your credentials', redirect(url_for('nereid.website.login')), 200 ) elif form.errors: if request.is_xhr or request.is_json: return jsonify(error=form.errors), 400 flash(_('Invalid email address.')) return render_template('reset-password.jinja')
def reset_account(cls): """ Reset the password for the user. .. tip:: This does NOT reset the password, but just creates an activation code and sends the link to the email of the user. If the user uses the link, he can change his password. """ form = ResetAccountForm() if form.validate_on_submit(): try: nereid_user, = cls.search([ ('email', '=', form.email.data), ('company', '=', request.nereid_website.company.id), ]) except ValueError: return cls.build_response( 'Invalid email address', render_template('reset-password.jinja'), 400 ) nereid_user.send_reset_email() return cls.build_response( 'An email has been sent to your account for resetting' ' your credentials', redirect(url_for('nereid.website.login')), 200 ) elif form.errors: if request.is_xhr or request.is_json: return jsonify(error=form.errors), 400 flash(_('Invalid email address.')) return render_template('reset-password.jinja')
def edit_task(self): """ Edit the task """ Activity = Pool().get("nereid.activity") Work = Pool().get("timesheet.work") task = self.get_task(self.id) Work.write([task.work], {"name": request.form.get("name")}) self.write([task], {"comment": request.form.get("comment")}) Activity.create( [ { "actor": request.nereid_user.id, "object_": "project.work, %d" % task.id, "verb": "edited_task", "target": "project.work, %d" % task.parent.id, "project": task.parent.id, } ] ) if request.is_xhr: return jsonify({"success": True, "name": self.rec_name, "comment": self.comment}) return redirect(request.referrer)
def change_password(cls): """ Changes the password .. tip:: On changing the password, the user is logged out and the login page is thrown at the user """ form = ChangePasswordForm() if request.method == "POST" and form.validate(): if current_user.match_password(form.old_password.data): cls.write([current_user], {"password": form.password.data}) logout_user() return cls.build_response( "Your password has been successfully changed! " "Please login again", redirect(url_for("nereid.website.login")), 200, ) else: return cls.build_response( "The current password you entered is invalid", render_template("change-password.jinja", change_password_form=form), 400, ) if form.errors and (request.is_xhr or request.is_json): return jsonify(errors=form.errors), 400 return render_template("change-password.jinja", change_password_form=form)
def delete_from_cart(cls, line): """ Delete a line from the cart. The required argument in POST is: line_id : ID of the line Response: 'OK' if X-HTTPRequest else redirect to shopping cart """ SaleLine = Pool().get('sale.line') cart = cls.open_cart() if not cart.sale: abort(404) try: sale_line, = SaleLine.search([ ('id', '=', line), ('sale', '=', cart.sale.id), ]) except ValueError: message = 'Looks like the item is already deleted.' else: SaleLine.delete([sale_line]) message = 'The order item has been successfully removed.' cart_updated.send(cart) flash(_(message)) if request.is_xhr: return jsonify(message=message) return redirect(url_for('nereid.cart.view_cart'))
def render_task(cls, task_id, project_id): """ Renders the task in a project """ task = cls.get_task(task_id) comments = sorted( task.history + task.work.timesheet_lines + task.attachments + task.repo_commits, key=lambda x: x.create_date ) hours = {} for line in task.work.timesheet_lines: hours[line.employee] = hours.setdefault(line.employee, 0) + line.hours if request.is_xhr: response = cls.serialize(task) with Transaction().set_context(task=task_id): response["comments"] = [comment.serialize("listing") for comment in comments] return jsonify(response) return render_template( "project/task.jinja", task=task, active_type_name="render_task_list", project=task.parent, comments=comments, timesheet_summary=hours, )
def change_constraint_dates(cls, task_id): """ Change the constraint dates """ Activity = Pool().get("nereid.activity") task = cls.get_task(task_id) data = {"constraint_start_time": False, "constraint_finish_time": False} constraint_start = request.form.get("constraint_start_time", None) constraint_finish = request.form.get("constraint_finish_time", None) if constraint_start: data["constraint_start_time"] = datetime.strptime(constraint_start, "%m/%d/%Y") if constraint_finish: data["constraint_finish_time"] = datetime.strptime(constraint_finish, "%m/%d/%Y") cls.write([task], data) Activity.create( [ { "actor": request.nereid_user.id, "object_": "project.work, %d" % task.id, "verb": "changed_date", "project": task.parent.id, } ] ) if request.is_xhr: return jsonify({"success": True}) flash("The constraint dates have been changed for this task.") return redirect(request.referrer)
def delete_task(cls, task_id): """ Delete the task from project Tasks can be deleted only if 1. The user is project admin 2. The user is an admin member in the project :param task_id: Id of the task to be deleted """ task = cls.get_task(task_id) # Check if user is among the project admins if not request.nereid_user.is_admin_of_project(task.parent): flash( "Sorry! You are not allowed to delete tasks. \ Contact your project admin for the same." ) return redirect(request.referrer) cls.write([task], {"active": False}) if request.is_xhr: return jsonify({"success": True}) flash("The task has been deleted") return redirect(url_for("project.work.render_project", project_id=task.parent.id))
def add_to_cart(cls): """ Adds the given item to the cart if it exists or to a new cart The form is expected to have the following data is post quantity : decimal product : integer ID action : set (default), add Response: 'OK' if X-HTTPRequest Redirect to shopping cart if normal request """ form = AddtoCartForm(request.form) if request.method == "POST" and form.validate(): cart = cls.open_cart(create_order=True) action = request.values.get("action", "set") if form.quantity.data <= 0: flash(_("Be sensible! You can only add real quantities to cart")) return redirect(url_for("nereid.cart.view_cart")) cls._add_or_update(cart.sale.id, form.product.data, form.quantity.data, action) if action == "add": flash(_("The product has been added to your cart"), "info") else: flash(_("Your cart has been updated with the product"), "info") if request.is_xhr: return jsonify(message="OK") return redirect(url_for("nereid.cart.view_cart"))
def delete_from_cart(cls, line): """ Delete a line from the cart. The required argument in POST is: line_id : ID of the line Response: 'OK' if X-HTTPRequest else redirect to shopping cart """ SaleLine = Pool().get('sale.line') cart = cls.open_cart() if not cart.sale: abort(404) try: sale_line, = SaleLine.search([ ('id', '=', line), ('sale', '=', cart.sale.id), ]) except ValueError: message = 'Looks like the item is already deleted.' else: SaleLine.delete([sale_line]) message = 'The order item has been successfully removed.' flash(_(message)) if request.is_xhr: return jsonify(message=message) return redirect(url_for('nereid.cart.view_cart'))
def edit_task(self): """ Edit the task """ Activity = Pool().get('nereid.activity') Work = Pool().get('timesheet.work') task = self.get_task(self.id) Work.write([task.work], { 'name': request.form.get('name'), }) self.write([task], {'comment': request.form.get('comment')}) Activity.create([{ 'actor': request.nereid_user.id, 'object_': 'project.work, %d' % task.id, 'verb': 'edited_task', 'target': 'project.work, %d' % task.parent.id, 'project': task.parent.id, }]) if request.is_xhr: return jsonify({ 'success': True, 'name': self.rec_name, 'comment': self.comment, }) return redirect(request.referrer)
def get_available_methods(cls): """Return the JSONified list of shipment gateways available This is a XHR only method If type is specified as address then an address lookup is done The get could be made with the following options: 1. address Checks if user is logged in Checks if its a valid address of the user extracts to_address from it 2. Individually specify the following: street, streetbis, city, postal_code, subdivision, country The subdivision and country are not expanded into the ISO codes or names because doing that may not be required by many methods and some methods may requrie codes while others require name. So it is better to pass the ID of the same and the get_rate method of each decide if they want to expand into CODE or NAME """ Address = Pool().get('party.address') if 'address' in request.args: if request.is_guest_user: abort(403) # If not validated as user's address this could lead to # exploitation by ID address_id = request.args.get('address', type=int) if address_id not in [ a.id for a in request.nereid_user.party.addresses ]: abort(403) address = Address(address_id) result = cls._get_available_methods( street=address.street, streetbis=address.streetbis, city=address.city, zip=address.zip, subdivision=address.subdivision.id, country=address.country.id, ) else: # Each specified manually result = cls._get_available_methods( street=request.args.get('street'), streetbis=request.args.get('streetbis'), city=request.args.get('city'), zip=request.args.get('zip'), subdivision=int(request.args.get('subdivision')), country=int(request.args.get('country')), ) return jsonify( result=[(g['id'], g['name'], g['amount']) for g in result] )
def country_list(cls): """ Return the list of countries in JSON """ return jsonify(result=[ {'key': c.id, 'value': c.name} for c in request.nereid_website.countries ])
def profile(cls): """ User profile """ if request.method == "GET" and request.is_xhr: user, = cls.browse([request.nereid_user.id]) return jsonify(user.serialize()) return super(NereidUser, cls).profile()
def profile(cls): """ User profile """ if request.method == "GET" and request.is_xhr: user, = cls.browse([request.nereid_user.id]) return jsonify(user._json()) return super(NereidUser, cls).profile()
def get_subdivisions(self): """ Returns serialized list of all subdivisions for current country """ Subdivision = Pool().get('country.subdivision') subdivisions = Subdivision.search([('country', '=', self.id)]) return jsonify(result=[s.serialize() for s in subdivisions])
def view_cart(cls): """Returns a view of the shopping cart This method only handles GET. Unlike previous versions the checkout method has been moved to nereid.checkout.x For XHTTP/Ajax Requests a JSON object with order and lines information which should be sufficient to show order information is returned. """ cart = cls.open_cart() if request.is_xhr: if not cart.sale: # Dont try to build further if the cart is empty return jsonify({'empty': True}) # Build locale formatters currency_format = partial(numbers.format_currency, currency=cart.sale.currency.code, locale=current_locale.language.code) number_format = partial(numbers.format_number, locale=current_locale.language.code) return jsonify( cart={ 'lines': [{ 'product': l.product and l.product.name or None, 'quantity': number_format(l.quantity), 'unit': l.unit.symbol, 'unit_price': currency_format(l.unit_price), 'amount': currency_format(l.amount), } for l in cart.sale.lines], 'empty': len(cart.sale.lines) > 0, 'total_amount': currency_format(cart.sale.total_amount), 'tax_amount': currency_format(cart.sale.tax_amount), 'untaxed_amount': currency_format(cart.sale.untaxed_amount), }) response = render_template('shopping-cart.jinja', cart=cart) response.headers['Cache-Control'] = 'max-age=0' return response
def update_task(self, task_id, project_id=None): """ Accepts a POST request against a task_id and updates the ticket :param task_id: The ID of the task which needs to be updated """ history_obj = Pool().get('project.work.history') task = self.get_task(task_id) history_data = { 'project': task.id, 'updated_by': request.nereid_user.id, 'comment': request.form['comment'] } updatable_attrs = ['state'] post_attrs = [request.form.get(attr, None) for attr in updatable_attrs] if any(post_attrs): # Combined update of task and history since there is some value # posted in addition to the comment task_changes = {} for attr in updatable_attrs: if getattr(task, attr) != request.form[attr]: task_changes[attr] = request.form[attr] if task_changes: # Only write change if anything has really changed self.write(task.id, task_changes) comment_id = self.browse(task.id).history[-1].id history_obj.write(comment_id, history_data) else: # just create comment since nothing really changed since this # update. This is to cover to cover cases where two users who # havent refreshed the web page close the ticket comment_id = history_obj.create(history_data) else: # Just comment, no update to task comment_id = history_obj.create(history_data) if request.nereid_user.id not in (p.id for p in task.participants): # Add the user to the participants if not already in the list self.write( task.id, {'participants': [('add', [request.nereid_user.id])]} ) if request.is_xhr: comment_record = history_obj.browse(comment_id) html = render_template('comment.jinja', comment=comment_record) return jsonify({ 'success': True, 'html': html, 'state': self.browse(task.id).state, }) return redirect(request.referrer)
def change_party(cls, party_id): """ Updates the current party of the nereid_user to the new party_id if it is one of the parties in the list of parties of the user :param party_id: ID of the party """ for party in current_user.parties: if party.id == party_id: cls.write([current_user], {'party': party.id}) break else: if request.is_xhr: return jsonify(error='The party is not valid'), 400 flash("The party is not valid") if request.is_xhr: return jsonify(success='Party has been changed successfully') return redirect( request.args.get('next', url_for('nereid.website.home')))
def cms_static_list(cls, page=1): """ Return JSON with list of all files inside cms static folder """ StaticFile = Pool().get("nereid.static.file") files = Pagination( StaticFile, [('folder', '=', current_website.cms_static_folder.id)], page, 10) return jsonify(items=[item.serialize() for item in files])
def mark_cancelled(self): """ Convert the lead as cancelled """ self.cancel([self]) if request.is_xhr or request.is_json: return jsonify({ 'success': True, 'message': 'The lead is cancelled.' }) return redirect(request.referrer)
def mark_converted(self): """ Convert the opportunity """ self.convert([self]) if request.is_xhr or request.is_json: return jsonify({ 'success': True, 'message': 'Awesome! The Opportunity is converted.' }) return redirect(request.referrer)
def mark_lead(self): """ Convert the opportunity to lead """ self.lead([self]) if request.is_xhr or request.is_json: return jsonify({ 'success': True, 'message': 'The lead is marked back to open.' }) return redirect(request.referrer)
def mark_lost(self): """ Convert the lead to lost """ self.lost([self]) if request.is_xhr or request.is_json: return jsonify({ 'success': True, 'message': 'The lead is marked as lost.' }) return redirect(request.referrer)
def subdivision_list(cls): """ Return the list of states for given country """ Subdivision = Pool().get('country.subdivision') country = int(request.args.get('country', 0)) if country not in [c.id for c in request.nereid_website.countries]: abort(404) subdivisions = Subdivision.search([('country', '=', country)]) return jsonify(result=[s.serialize() for s in subdivisions])
def get_auth_token(cls): """ A method that returns a login token and user information in a json response. This should probably be called with basic authentication in the header. The token generated could then be used for subsequent requests. """ return jsonify({ 'user': current_user.serialize(), 'token': current_user.get_auth_token(), })