def send_suggestion_approved_email(journal_name, email): url_root = request.url_root if url_root.endswith("/"): url_root = url_root[:-1] to = [email] fro = app.config.get('SYSTEM_EMAIL_FROM', '*****@*****.**') subject = app.config.get("SERVICE_NAME","") + " - journal accepted" try: if app.config.get("ENABLE_PUBLISHER_EMAIL", False): app_email.send_mail(to=to, fro=fro, subject=subject, template_name="email/suggestion_accepted.txt", journal_name=journal_name.encode('utf-8', 'replace'), url_root=url_root ) flash('Sent email to ' + email + ' to tell them about their journal getting accepted into DOAJ.', 'success') else: flash('Did not send email to ' + email + ' to tell them about their journal getting accepted into DOAJ, as publisher emails are disabled.', 'error') except Exception as e: magic = str(uuid.uuid1()) util.flash_with_url('Hm, sending the journal acceptance information email didn\'t work. Please quote this magic number when reporting the issue: ' + magic + ' . Thank you!', 'error') app.logger.error(magic + "\n" + repr(e)) raise e
def forgot(): if request.method == "POST": # get hold of the user account un = request.form.get("un", "") account = models.Account.pull(un) if account is None: account = models.Account.pull_by_email(un) if account is None: util.flash_with_url("Hm, sorry, your account username / email address is not recognised.", "error") return render_template("account/forgot.html") if not account.data.get("email"): util.flash_with_url("Hm, sorry, your account does not have an associated email address.", "error") return render_template("account/forgot.html") # if we get to here, we have a user account to reset reset_token = uuid.uuid4().hex account.set_reset_token(reset_token, app.config.get("PASSWORD_RESET_TIMEOUT", 86400)) account.save() sep = "/" if request.url_root.endswith("/"): sep = "" reset_url = request.url_root + sep + "account/reset/" + reset_token to = [account.data["email"], app.config["ADMIN_EMAIL"]] fro = app.config["ADMIN_EMAIL"] subject = app.config.get("SERVICE_NAME", "") + " - password reset" text = "A password reset request for account '" + account.id + "' has been received and processed.\n\n" text += "Please visit " + reset_url + " and enter your new password.\n\n" text += ( "If you are the user '" + account.id + "' and you requested this change, please visit that link now and set the password to something of your preference.\n\n" ) text += ( "If you are the user '" + account.id + "' and you did not request this change, you can ignore this email.\n\n" ) text += "Regards, The OpenDOAR Team" try: util.send_mail(to=to, fro=fro, subject=subject, text=text) flash("Instructions to reset your password have been sent to you. Please check your emails.") if app.config.get("DEBUG", False): flash("Debug mode - url for reset is " + reset_url) except Exception as e: flash("Hm, sorry - sending the password reset email didn't work.", "error") if app.config.get("DEBUG", False): flash("Debug mode - url for reset is" + reset_url) # app.logger.error(magic + "\n" + repr(e)) return render_template("account/forgot.html")
def journal_page(journal_id): # user must have the role "edit_journal" if not current_user.has_role("edit_journal"): abort(401) # get the journal, so we can check our permissions against it j = models.Journal.pull(journal_id) if j is None: abort(404) # user must be either the "admin.editor" of the journal, or the editor of the "admin.editor_group" # is the user the currently assigned editor of the journal? passed = False if j.editor == current_user.id: passed = True # now check whether the user is the editor of the editor group role = "associate_editor" eg = models.EditorGroup.pull_by_key("name", j.editor_group) if eg is not None and eg.editor == current_user.id: passed = True role = "editor" # if the user wasn't the editor or the owner of the editor group, unauthorised if not passed: abort(401) # attempt to get a lock on the object try: lockinfo = lock.lock("journal", journal_id, current_user.id) except lock.Locked as l: return render_template("editor/journal_locked.html", journal=j, lock=l.lock, edit_journal_page=True) if request.method == "GET": fc = formcontext.JournalFormFactory.get_form_context(role=role, source=j) return fc.render_template(edit_journal_page=True, lock=lockinfo) elif request.method == "POST": fc = formcontext.JournalFormFactory.get_form_context(role=role, form_data=request.form, source=j) if fc.validate(): try: fc.finalise() flash('Journal updated.', 'success') for a in fc.alert: flash_with_url(a, "success") return redirect(url_for("editor.journal_page", journal_id=j.id, _anchor='done')) except formcontext.FormContextException as e: flash(e.message) return redirect(url_for("editor.journal_page", journal_id=j.id, _anchor='cannot_edit')) else: return fc.render_template(edit_journal_page=True, lock=lockinfo)
def journal_page(journal_id): # user must have the role "edit_journal" if not current_user.has_role("edit_journal"): abort(401) # get the journal, so we can check our permissions against it j = models.Journal.pull(journal_id) if j is None: abort(404) # user must be either the "admin.editor" of the journal, or the editor of the "admin.editor_group" # is the user the currently assigned editor of the journal? passed = False if j.editor == current_user.id: passed = True # now check whether the user is the editor of the editor group role = "associate_editor" eg = models.EditorGroup.pull_by_key("name", j.editor_group) if eg is not None and eg.editor == current_user.id: passed = True role = "editor" # if the user wasn't the editor or the owner of the editor group, unauthorised if not passed: abort(401) # attempt to get a lock on the object try: lockinfo = lock.lock("journal", journal_id, current_user.id) except lock.Locked as l: return render_template("editor/journal_locked.html", journal=j, lock=l.lock, edit_journal_page=True) if request.method == "GET": fc = formcontext.JournalFormFactory.get_form_context(role=role, source=j) return fc.render_template(edit_journal_page=True, lock=lockinfo) elif request.method == "POST": fc = formcontext.JournalFormFactory.get_form_context(role=role, form_data=request.form, source=j) if fc.validate(): try: fc.finalise() flash('Journal updated.', 'success') for a in fc.alert: flash_with_url(a, "success") return redirect(url_for("editor.journal_page", journal_id=j.id, _anchor='done')) except formcontext.FormContextException as e: flash(str(e)) return redirect(url_for("editor.journal_page", journal_id=j.id, _anchor='cannot_edit')) else: return fc.render_template(edit_journal_page=True, lock=lockinfo)
def journal_page(journal_id): if not current_user.has_role("edit_journal"): abort(401) ap = models.Journal.pull(journal_id) if ap is None: abort(404) # attempt to get a lock on the object try: lockinfo = lock.lock("journal", journal_id, current_user.id) except lock.Locked as l: return render_template("admin/journal_locked.html", journal=ap, lock=l.lock, edit_journal_page=True) if request.method == "GET": job = None job_id = request.values.get("job") if job_id is not None and job_id != "": job = models.BackgroundJob.pull(job_id) fc = formcontext.JournalFormFactory.get_form_context(role="admin", source=ap) return fc.render_template(edit_journal_page=True, lock=lockinfo, job=job) elif request.method == "POST": fc = formcontext.JournalFormFactory.get_form_context( role="admin", form_data=request.form, source=ap) if fc.validate(): try: fc.finalise() flash('Journal updated.', 'success') for a in fc.alert: flash_with_url(a, "success") return redirect( url_for("admin.journal_page", journal_id=ap.id, _anchor='done')) except formcontext.FormContextException as e: flash(str(e)) return redirect( url_for("admin.journal_page", journal_id=ap.id, _anchor='cannot_edit')) else: return fc.render_template(edit_journal_page=True, lock=lockinfo)
def suggestion_page(suggestion_id): if not current_user.has_role("edit_suggestion"): abort(401) ap = models.Suggestion.pull(suggestion_id) if ap is None: abort(404) # attempt to get a lock on the object try: lockinfo = lock.lock("suggestion", suggestion_id, current_user.id) except lock.Locked as l: return render_template("admin/suggestion_locked.html", suggestion=ap, lock=l.lock, edit_suggestion_page=True) if request.method == "GET": fc = formcontext.ApplicationFormFactory.get_form_context(role="admin", source=ap) return fc.render_template(edit_suggestion_page=True, lock=lockinfo) elif request.method == "POST": fc = formcontext.ApplicationFormFactory.get_form_context( role="admin", form_data=request.form, source=ap) if fc.validate(): try: fc.finalise() flash('Application updated.', 'success') for a in fc.alert: flash_with_url(a, "success") return redirect( url_for("admin.suggestion_page", suggestion_id=ap.id, _anchor='done')) except formcontext.FormContextException as e: flash(str(e)) return redirect( url_for("admin.suggestion_page", suggestion_id=ap.id, _anchor='cannot_edit')) else: return fc.render_template(edit_suggestion_page=True, lock=lockinfo)
def forgot(): if request.method == 'POST': # get hold of the user account un = request.form.get('un', "") account = models.Account.pull(un) if account is None: account = models.Account.pull_by_email(un) if account is None: util.flash_with_url('Your account email address is not recognised.', 'error') return render_template('account/forgot.html') if account.is_deleted(): util.flash_with_url('Your account email address is not recognised.', 'error') return render_template('account/forgot.html') if account.is_banned(): flash('This account is banned from the service', 'error') return render_template('account/forgot.html') if not account.data.get('email'): util.flash_with_url('Your account does not have an associated email address.', 'error') return render_template('account/forgot.html') # if we get to here, we have a user account to reset reset_token = uuid.uuid4().hex account.set_reset_token(reset_token, app.config.get("PASSWORD_RESET_TIMEOUT", 86400)) account.save() sep = "/" if request.url_root.endswith("/"): sep = "" reset_url = request.url_root + sep + "account/reset/" + reset_token to = [account.data['email'], app.config['FEEDBACK_EMAIL']] fro = app.config['FEEDBACK_EMAIL'] subject = app.config.get("SERVICE_NAME", "") + " - password reset" text = "A password reset request for account '" + account.id + "' has been received and processed.\n\n" text += "Please visit " + reset_url + " and enter your new password.\n\n" text += "If you are the user " + account.id + " and you requested this change, please visit that link now and set the password to something of your preference.\n\n" text += "If you are the user " + account.id + " and you did not request this change, you can ignore this email.\n\n" text += "Regards, The UniBoard Team" try: util.send_mail(to=to, fro=fro, subject=subject, text=text) flash('Instructions to reset your password have been sent to you. Please check your emails.', "success") if app.config.get('DEBUG', False): flash('Debug mode - url for reset is ' + reset_url, "error") except Exception as e: flash('Hm, sorry - sending the password reset email didn\'t work.', 'error') if app.config.get('DEBUG', False): flash('Debug mode - url for reset is' + reset_url, "error") # app.logger.error(magic + "\n" + repr(e)) return render_template('account/forgot.html')
def forgot(): CONTACT_INSTR = ' Please <a href="{url}">contact us.</a>'.format(url=url_for('doaj.contact')) if request.method == 'POST': # get hold of the user account un = request.form.get('un',"") account = models.Account.pull(un) if account is None: account = models.Account.pull_by_email(un) if account is None: util.flash_with_url('Hm, sorry, your account username / email address is not recognised.' + CONTACT_INSTR, 'error') return render_template('account/forgot.html') if not account.data.get('email'): util.flash_with_url('Hm, sorry, your account does not have an associated email address.' + CONTACT_INSTR, 'error') return render_template('account/forgot.html') # if we get to here, we have a user account to reset #newpass = util.generate_password() #account.set_password(newpass) reset_token = uuid.uuid4().hex account.set_reset_token(reset_token, app.config.get("PASSWORD_RESET_TIMEOUT", 86400)) account.save() sep = "/" if request.url_root.endswith("/"): sep = "" reset_url = request.url_root + sep + "account/reset/" + reset_token to = [account.data['email']] fro = app.config.get('SYSTEM_EMAIL_FROM', app.config['ADMIN_EMAIL']) subject = app.config.get("SERVICE_NAME","") + " - password reset" try: app_email.send_mail(to=to, fro=fro, subject=subject, template_name="email/password_reset.txt", account_id=account.id, reset_url=reset_url, ) flash('Instructions to reset your password have been sent to you. Please check your emails.') if app.config.get('DEBUG',False): flash('Debug mode - url for reset is ' + reset_url) except Exception as e: magic = str(uuid.uuid1()) util.flash_with_url('Hm, sorry - sending the password reset email didn\'t work.' + CONTACT_INSTR + ' It would help us if you also quote this magic number: ' + magic + ' . Thank you!', 'error') if app.config.get('DEBUG',False): flash('Debug mode - url for reset is ' + reset_url) app.logger.error(magic + "\n" + repr(e)) return render_template('account/forgot.html')
def forgot(): CONTACT_INSTR = ' Please <a href="{url}">contact us.</a>'.format(url=url_for('doaj.contact')) if request.method == 'POST': # get hold of the user account un = request.form.get('un', "") account = models.Account.pull(un) if account is None: account = models.Account.pull_by_email(un) if account is None: util.flash_with_url('Hm, sorry, your account username / email address is not recognised.' + CONTACT_INSTR, 'error') return render_template('account/forgot.html') if not account.data.get('email'): util.flash_with_url('Hm, sorry, your account does not have an associated email address.' + CONTACT_INSTR, 'error') return render_template('account/forgot.html') # if we get to here, we have a user account to reset #newpass = util.generate_password() #account.set_password(newpass) reset_token = uuid.uuid4().hex account.set_reset_token(reset_token, app.config.get("PASSWORD_RESET_TIMEOUT", 86400)) account.save() sep = "/" if request.url_root.endswith("/"): sep = "" reset_url = request.url_root + sep + "account/reset/" + reset_token to = [account.data['email']] fro = app.config.get('SYSTEM_EMAIL_FROM', app.config['ADMIN_EMAIL']) subject = app.config.get("SERVICE_NAME", "") + " - password reset" try: app_email.send_mail(to=to, fro=fro, subject=subject, template_name="email/password_reset.txt", account_id=account.id, reset_url=reset_url, ) flash('Instructions to reset your password have been sent to you. Please check your emails.') if app.config.get('DEBUG', False): flash('Debug mode - url for reset is ' + reset_url) except Exception as e: magic = str(uuid.uuid1()) util.flash_with_url('Hm, sorry - sending the password reset email didn\'t work.' + CONTACT_INSTR + ' It would help us if you also quote this magic number: ' + magic + ' . Thank you!', 'error') if app.config.get('DEBUG', False): flash('Debug mode - url for reset is ' + reset_url) app.logger.error(magic + "\n" + repr(e)) return render_template('account/forgot.html')
def suggestion_form(form, request, template_name, existing_suggestion=None, success_url=None, process_the_form=True, group_editable=False, editorial_available=False, redirect_route=None, lock=None, **kwargs): first_field_with_error = '' #import json #print json.dumps(request.form, indent=3) #import json #print json.dumps(form.data, indent=3) # the code below will output only submitted values which were truthy # useful for debugging the form itself without getting lost in the # 57-field object that gets created #print #print #for field in form: # #if field.data and field.data != 'None': # if field.short_name == 'subject': # print field.short_name, '::', field.data, ',', type(field.data) #print if request.method == 'POST': if not process_the_form: if existing_suggestion: # this is not a success, so we do not consider the success_url return redirect(url_for(redirect_route, suggestion_id=existing_suggestion.id, _anchor='cannot_edit')) else: #if form.make_all_fields_optional.data: # valid = True #else: # valid = form.validate() valid = form.validate() if valid: email_editor = False if group_editable: email_editor = SuggestionFormXWalk.is_new_editor_group(form, existing_suggestion) email_associate = False if editorial_available: email_associate = SuggestionFormXWalk.is_new_editor(form, existing_suggestion) # do the core crosswalk suggestion = SuggestionFormXWalk.form2obj(form, existing_suggestion) now = datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ") if not existing_suggestion: suggestion.suggested_on = now suggestion.set_application_status('pending') else: # copy over any important fields from the previous version of the object created_date = existing_suggestion.created_date if existing_suggestion.created_date else now suggestion.set_created(created_date) suggestion.suggested_on = existing_suggestion.suggested_on suggestion.data['id'] = existing_suggestion.data['id'] if ((suggestion.owner is None or suggestion.owner == "") and (existing_suggestion.owner is not None)) or not current_user.has_role("admin"): suggestion.set_owner(existing_suggestion.owner) if not group_editable or not editorial_available: suggestion.set_editor_group(existing_suggestion.editor_group) if not editorial_available: suggestion.set_editor(existing_suggestion.editor) # FIXME: probably should check that the editor is in the editor_group and remove if not # the code below can be used to quickly debug objects which # fail to serialise as JSON - there should be none of those # in the suggestion! ''' import json for thing in suggestion.data: try: if thing == 'bibjson': bibjson = suggestion.bibjson().bibjson for thing2 in bibjson: try: print json.dumps(bibjson[thing2]) except TypeError as e: print 'This is it:',thing2 print e print print json.dumps(bibjson[thing2]) except TypeError as e: print 'This is it:',thing print e print ''' # the code below produces a dump of the object returned by # the crosswalk ''' import json print print print 'Now all the data!' print json.dumps(suggestion.data, indent=3) ''' suggestion.save() if existing_suggestion: flash('Application updated.', 'success') if suggestion.application_status == 'accepted': # this suggestion is just getting accepted j = journal.suggestion2journal(suggestion) j.set_in_doaj(True) j.save() qobj = j.make_query(q=j.id) jurl = url_for('admin.admin_site_search') + '?source=' + json.dumps(qobj).replace('"', '"') flash_with_url('<a href="{url}" target="_blank">New journal created</a>.'.format(url=jurl), 'success') owner = create_account_on_suggestion_approval(suggestion, j) send_suggestion_approved_email(j.bibjson().title, owner.email) # only actually send the email when we've successfully processed the form if email_editor: send_editor_group_email(suggestion) if email_associate: send_editor_email(suggestion) if success_url: return redirect(success_url) else: return redirect(url_for(redirect_route, suggestion_id=suggestion.id, _anchor='done')) else: for field in form: # in order of definition of fields, so the order of rendering should be (manually) kept the same as the order of definition for this to work if field.errors: first_field_with_error = field.short_name print "field with error", first_field_with_error break return render_template( template_name, form=form, first_field_with_error=first_field_with_error, q_numbers=xrange(1, 10000).__iter__(), # a generator for the purpose of displaying numbered questions other_val=other_val, digital_archiving_policy_specific_library_value=digital_archiving_policy_specific_library_value, edit_suggestion_page=True, group_editable=group_editable, editorial_available=editorial_available, lock=lock, **kwargs )
def create_account_on_suggestion_approval(suggestion, journal): o = Account.pull(suggestion.owner) if o: flash('Account {username} already exists, so simply associating the new journal with it.'.format(username=o.id), 'success') o.add_journal(journal.id) if not o.has_role('publisher'): o.add_role('publisher') o.save() return o suggestion_contact = util.listpop(suggestion.contacts()) if not suggestion_contact.get('email'): msg = ERROR_MSG_TEMPLATE.format(username=o.id, missing_thing='journal contact email in the application') app.logger.error(msg) flash(msg) return o send_info_to = suggestion_contact.get('email') o = Account.make_account( suggestion.owner, name=suggestion_contact.get('name'), email=send_info_to, roles=['publisher'], associated_journal_ids=[journal.id] ) o.save() url_root = request.url_root if url_root.endswith("/"): url_root = url_root[:-1] if not o.reset_token: msg = ERROR_MSG_TEMPLATE.format(username=o.id, missing_thing='reset token') app.logger.error(msg) flash(msg) return o reset_url = url_root + url_for('account.reset', reset_token=o.reset_token) forgot_pw_url = url_root + url_for('account.forgot') password_create_timeout_seconds = int(app.config.get("PASSWORD_CREATE_TIMEOUT", app.config.get('PASSWORD_RESET_TIMEOUT', 86400) * 14)) password_create_timeout_days = password_create_timeout_seconds / (60*60*24) to = [send_info_to] fro = app.config.get('SYSTEM_EMAIL_FROM', '*****@*****.**') subject = app.config.get("SERVICE_NAME","") + " - account created" try: if app.config.get("ENABLE_PUBLISHER_EMAIL", False): app_email.send_mail(to=to, fro=fro, subject=subject, template_name="email/account_created.txt", reset_url=reset_url, username=o.id, timeout_days=password_create_timeout_days, forgot_pw_url=forgot_pw_url ) flash('Sent email to ' + send_info_to + ' to tell them about the new account.', 'success') else: flash('Did not email to ' + send_info_to + ' to tell them about the new account, as publisher emailing is disabled.', 'error') if app.config.get('DEBUG',False): util.flash_with_url('Debug mode - url for create is <a href="{url}">{url}</a>'.format(url=reset_url)) except Exception as e: magic = str(uuid.uuid1()) util.flash_with_url('Hm, sending the account creation email didn\'t work. Please quote this magic number when reporting the issue: ' + magic + ' . Thank you!', 'error') if app.config.get('DEBUG',False): util.flash_with_url('Debug mode - url for create is <a href="{url}">{url}</a>'.format(url=reset_url)) app.logger.error(magic + "\n" + repr(e)) raise e flash('Account {username} created'.format(username=o.id), 'success') return o