def caption(self): """Returns a case caption for the case, for inclusion in documents.""" #logmessage("caption: gathering first party") #logmessage("caption: case action_type is " + self.case.action_type) #logmessage("caption: case instanceName is " + self.case.instanceName) #logmessage("caption: instanceName is " + self.case.firstParty.instanceName) self.case.firstParty.gather() #logmessage("caption: gathered first party") if not self.case.is_solo_action: #logmessage("caption: case is solo action") self.case.secondParty.gather() output = "" #logmessage("caption: going to call in_the_court") output += "[BOLDCENTER] " + self.case.court.in_the_court(legalfiling=self, case=self.case) + "\n\n" output += "[BEGIN_CAPTION]" if self.case.action_type == 'in re': output += 'In re ' output += comma_and_list(self.case.firstParty.elements, comma_string=",[NEWLINE]", and_string=word('and'), before_and=" ", after_and='[NEWLINE]') + ",[NEWLINE]" if self.case.action_type != 'in re': output += "[TAB][TAB]" + word(self.case.firstParty.as_noun()).capitalize() + "[NEWLINE] " if not self.case.is_solo_action: output += "[SKIPLINE][TAB]" + word('v.') + " [NEWLINE][SKIPLINE] " output += comma_and_list(self.case.secondParty.elements, comma_string=",[NEWLINE]", and_string=word('and'), before_and=" ", after_and='[NEWLINE]') + ",[NEWLINE]" output += "[TAB][TAB]" + word(self.case.secondParty.as_noun()).capitalize() output += "[VERTICAL_LINE]" output += self.case.case_id_in_caption(legalfiling=self) output += "[END_CAPTION]\n\n" if self.title is not None: output += "[BOLDCENTER] " + self.title.upper() + "\n" return(output)
def edit_user_profile_page(id): user = UserModel.query.filter_by(id=id).first() the_tz = user.timezone if user.timezone else get_default_timezone() if user is None: abort(404) if 'disable_mfa' in request.args and int(request.args['disable_mfa']) == 1: user.otp_secret = None db.session.commit() #docassemble.webapp.daredis.clear_user_cache() return redirect(url_for('edit_user_profile_page', id=id)) if 'reset_email_confirmation' in request.args and int(request.args['reset_email_confirmation']) == 1: user.confirmed_at = None db.session.commit() #docassemble.webapp.daredis.clear_user_cache() return redirect(url_for('edit_user_profile_page', id=id)) the_role_id = list() for role in user.roles: the_role_id.append(text_type(role.id)) if len(the_role_id) == 0: the_role_id = [text_type(Role.query.filter_by(name='user').first().id)] form = EditUserProfileForm(request.form, obj=user, role_id=the_role_id) if request.method == 'POST' and form.cancel.data: flash(word('The user profile was not changed.'), 'success') return redirect(url_for('user_list')) if user.social_id.startswith('local$'): form.role_id.choices = [(r.id, r.name) for r in db.session.query(Role).filter(Role.name != 'cron').order_by('name')] privileges_note = None else: form.role_id.choices = [(r.id, r.name) for r in db.session.query(Role).filter(and_(Role.name != 'cron', Role.name != 'admin')).order_by('name')] privileges_note = word("Note: only users with e-mail/password accounts can be given admin privileges.") form.timezone.choices = [(x, x) for x in sorted([tz for tz in pytz.all_timezones])] form.timezone.default = the_tz if text_type(form.timezone.data) == 'None' or text_type(form.timezone.data) == '': form.timezone.data = the_tz if user.otp_secret is None: form.uses_mfa.data = False else: form.uses_mfa.data = True admin_id = Role.query.filter_by(name='admin').first().id if request.method == 'POST' and form.validate(user.id, admin_id): form.populate_obj(user) roles_to_remove = list() the_role_id = list() for role in user.roles: roles_to_remove.append(role) for role in roles_to_remove: user.roles.remove(role) for role in Role.query.order_by('id'): if role.id in form.role_id.data: user.roles.append(role) the_role_id.append(role.id) db.session.commit() #docassemble.webapp.daredis.clear_user_cache() flash(word('The information was saved.'), 'success') return redirect(url_for('user_list')) form.role_id.default = the_role_id confirmation_feature = True if user.id > 2 else False return render_template('users/edit_user_profile_page.html', version_warning=None, page_title=word('Edit User Profile'), tab_title=word('Edit User Profile'), form=form, confirmation_feature=confirmation_feature, privileges_note=privileges_note, is_self=(user.id == current_user.id))
def recursively_add_fields(fields, id_to_page, outfields, prefix=''): for i in fields: field = resolve1(i) name, value, rect, page, field_type = field.get('T'), field.get('V'), field.get('Rect'), field.get('P'), field.get('FT') if name is not None: if PY2: name = remove_nonprintable_limited(str(name)) else: if not isinstance(name, bytes): name = bytes(str(name), encoding='utf-8') name = remove_nonprintable_bytes_limited(name) if value is not None: if PY2: value = remove_nonprintable_limited(str(value)) else: if not isinstance(value, bytes): value = bytes(str(value), encoding='utf-8') value = remove_nonprintable_bytes_limited(value) #logmessage("name is " + repr(name) + " and FT is |" + repr(str(field_type)) + "| and value is " + repr(value)) if page is not None: pageno = id_to_page[page.objid] else: pageno = 1 if str(field_type) in ('/Btn', "/u'Btn'", "/'Btn'"): if value == '/Yes': default = "Yes" else: default = "No" elif str(field_type) in ('/Sig', "/u'Sig'", "/'Sig'"): default = '${ user.signature }' else: if value is not None: #for val in value: # logmessage("Got a " + str(ord(val))) #logmessage(repr(value.decode('utf8'))) #default = re.sub(r'^\xc3\xbe\xc3\xbf', '', value) default = value if not default: default = word("something") else: default = word("something") kids = field.get('Kids') if kids: if name is None: recursively_add_fields(kids, id_to_page, outfields, prefix=prefix) else: if prefix == '': recursively_add_fields(kids, id_to_page, outfields, prefix=name) else: recursively_add_fields(kids, id_to_page, outfields, prefix=prefix + '.' + name) else: if prefix != '' and name is not None: outfields.append((prefix + '.' + name, default, pageno, rect, field_type)) elif prefix == '': outfields.append((name, default, pageno, rect, field_type)) else: outfields.append((prefix, default, pageno, rect, field_type))
def invite(): """ Allows users to send invitations to register an account """ user_manager = current_app.user_manager next = request.args.get('next', _endpoint_url(user_manager.after_invite_endpoint)) user_role = Role.query.filter_by(name='user').first() invite_form = MyInviteForm(request.form) invite_form.role_id.choices = [(text_type(r.id), text_type(r.name)) for r in db.session.query(Role).filter(and_(Role.name != 'cron', Role.name != 'admin')).order_by('name')] invite_form.role_id.default = text_type(user_role.id) if text_type(invite_form.role_id.data) == 'None': invite_form.role_id.data = text_type(user_role.id) if request.method=='POST' and invite_form.validate(): email = invite_form.email.data the_role_id = None for role in Role.query.order_by('id'): if role.id == int(invite_form.role_id.data) and role.name != 'admin' and role.name != 'cron': the_role_id = role.id if the_role_id is None: the_role_id = user_role.id user, user_email = user_manager.find_user_by_email(email) if user: flash(word("A user with that e-mail has already registered"), "error") return redirect(url_for('invite')) else: user_invite = MyUserInvitation(email=email, role_id=the_role_id, invited_by_user_id=current_user.id) db.session.add(user_invite) db.session.commit() token = user_manager.generate_token(user_invite.id) accept_invite_link = url_for('user.register', token=token, _external=True) user_invite.token = token db.session.commit() #docassemble.webapp.daredis.clear_user_cache() try: logmessage("Trying to send e-mail to " + text_type(user_invite.email)) emails.send_invite_email(user_invite, accept_invite_link) except Exception as e: logmessage("Failed to send e-mail") db.session.delete(user_invite) db.session.commit() #docassemble.webapp.daredis.clear_user_cache() flash(word('Unable to send e-mail. Error was: ') + text_type(e), 'error') return redirect(url_for('invite')) flash(word('Invitation has been sent.'), 'success') return redirect(next) return render_template('flask_user/invite.html', version_warning=None, bodyclass='adminbody', page_title=word('Invite User'), tab_title=word('Invite User'), form=invite_form)
def populate_tables(): user_manager = UserManager(SQLAlchemyAdapter(db, UserModel, UserAuthClass=UserAuthModel), app) admin_defaults = daconfig.get('default admin account', dict()) if 'email' not in admin_defaults: admin_defaults['email'] = '*****@*****.**' if 'nickname' not in admin_defaults: admin_defaults['nickname'] = 'admin' if 'first_name' not in admin_defaults: admin_defaults['first_name'] = word('System') if 'last_name' not in admin_defaults: admin_defaults['last_name'] = word('Administrator') cron_defaults = daconfig.get('default cron account', {'nickname': 'cron', 'email': '*****@*****.**', 'first_name': 'Cron', 'last_name': 'User'}) cron_defaults['active'] = False user_role = get_role(db, 'user') admin_role = get_role(db, 'admin') cron_role = get_role(db, 'cron') customer_role = get_role(db, 'customer') developer_role = get_role(db, 'developer') advocate_role = get_role(db, 'advocate') trainer_role = get_role(db, 'trainer') for user in UserModel.query.all(): if len(user.roles) == 0: user.roles.append(user_role) db.session.commit() admin = get_user(db, admin_role, admin_defaults) cron = get_user(db, cron_role, cron_defaults) if admin.confirmed_at is None: admin.confirmed_at = datetime.datetime.now() if cron.confirmed_at is None: cron.confirmed_at = datetime.datetime.now() db.session.commit() add_dependencies(admin.id) git_packages = Package.query.filter_by(type='git') for package in git_packages: if package.name in ['docassemble', 'docassemble.base', 'docassemble.webapp', 'docassemble.demo']: package.giturl = None package.gitsubdir = None package.type = 'pip' db.session.commit() # docassemble_git_url = daconfig.get('docassemble git url', 'https://github.com/jhpyle/docassemble') # installed_packages = get_installed_distributions() # existing_packages = [package.name for package in Package.query.all()] # for package in installed_packages: # if package.key in existing_packages: # continue # package_auth = PackageAuth(user_id=admin.id) # if package.key in ['docassemble', 'docassemble.base', 'docassemble.webapp', 'docassemble.demo']: # package_entry = Package(name=package.key, package_auth=package_auth, giturl=docassemble_git_url, packageversion=package.version, gitsubdir=re.sub(r'\.', '_', package.key), type='git', core=True) # else: # package_entry = Package(name=package.key, package_auth=package_auth, packageversion=package.version, type='pip', core=True) # db.session.add(package_auth) # db.session.add(package_entry) return
def case_id_in_caption(self, **kwargs): """Returns the text for the case ID that will appear in the case caption. """ result = run_hook('case', self, 'case_id_in_caption', self.court.jurisdiction, **kwargs) if result is None: if hasattr(self, 'case_id'): return word('Case No.') + " " + self.case.case_id else: return word('Case No.') return result
def add_privilege(): form = NewPrivilegeForm(request.form, obj=current_user) if request.method == 'POST' and form.validate(): for role in db.session.query(Role).order_by(Role.name): if role.name == form.name.data: flash(word('The privilege could not be added because it already exists.'), 'error') return redirect(url_for('privilege_list')) db.session.add(Role(name=form.name.data)) db.session.commit() flash(word('The privilege was added.'), 'success') return redirect(url_for('privilege_list')) return render_template('users/new_role_page.html', version_warning=None, bodyclass='adminbody', page_title=word('Add Privilege'), tab_title=word('Add Privilege'), form=form)
def to_text(html_doc): #logmessage("Starting to_text") output = text_type() soup = BeautifulSoup(html_doc, 'html.parser') [s.extract() for s in soup(['style', 'script', '[document]', 'head', 'title', 'audio', 'video', 'pre', 'attribution'])] [s.extract() for s in soup.find_all(hidden)] [s.extract() for s in soup.find_all('div', {'class': 'invisible'})] previous = text_type() for s in soup.find_all(do_show): if s.name in ['input', 'textarea', 'img'] and s.has_attr('alt'): words = s.attrs['alt'] if s.has_attr('placeholder'): words += text_type(", ") + s.attrs['placeholder'] else: words = s.get_text() words = re.sub(r'\n\s*', ' ', words, flags=re.DOTALL) if len(words) and re.search(r'\w *$', words, re.UNICODE): words = words + text_type('.') if words != previous: output += text_type(words) + "\n" previous = words terms = dict() for s in soup.find_all('a'): if s.has_attr('class') and s.attrs['class'][0] == 'daterm' and s.has_attr('data-content') and s.string is not None: terms[s.string] = s.attrs['data-content'] if len(terms): output += word("Terms used in this question:") + "\n" for term, definition in terms.items(): output += text_type(term) + '. ' + text_type(definition) + '\n' output = re.sub(r'&gt;', '>', output) output = re.sub(r'&lt;', '<', output) output = re.sub(r'>', '>', output) output = re.sub(r'<', '<', output) output = re.sub(r'<[^>]+>', '', output) return output
def validate(self): rv = FlaskForm.validate(self) if not rv: return False if self.action.data not in ('edit', 'new'): return False has_error = False if self.action.data in ('edit', 'new'): if type(self.name.data) not in (str, unicode) or not re.search(r'[A-Za-z0-9]', self.name.data): self.name.errors.append(word("The name must be filled in.")) has_error = True if type(self.method.data) not in (str, unicode) or self.method.data not in ('referer', 'ip', 'none'): self.name.errors.append(word("You must select an option.")) has_error = True if has_error: return False return True
def validate(self, user_id, admin_id): rv = UserProfileForm.validate(self) if not rv: return False if current_user.id == user_id: if admin_id not in self.role_id.data: self.role_id.errors.append(word('You cannot take away your own admin privilege.')) return False return True
def user_add(): user_role = Role.query.filter_by(name='user').first() add_form = UserAddForm(request.form, role_id=[text_type(user_role.id)]) add_form.role_id.choices = [(r.id, r.name) for r in db.session.query(Role).filter(Role.name != 'cron').order_by('name')] add_form.role_id.default = user_role.id if text_type(add_form.role_id.data) == 'None': add_form.role_id.data = user_role.id if request.method == 'POST' and add_form.validate(): user, user_email = app.user_manager.find_user_by_email(add_form.email.data) if user: flash(word("A user with that e-mail has already registered"), "error") return redirect(url_for('user_add')) user_auth = UserAuthModel(password=app.user_manager.hash_password(add_form.password.data)) while True: new_social = 'local$' + random_alphanumeric(32) existing_user = UserModel.query.filter_by(social_id=new_social).first() if existing_user: continue break the_user = UserModel( active=True, nickname=re.sub(r'@.*', '', add_form.email.data), social_id=new_social, email=add_form.email.data, user_auth=user_auth, first_name = add_form.first_name.data, last_name = add_form.last_name.data, confirmed_at = datetime.datetime.now() ) num_roles = 0 for role in Role.query.order_by('id'): if role.id in add_form.role_id.data: the_user.roles.append(role) num_roles +=1 if num_roles == 0: the_user.roles.append(user_role) db.session.add(user_auth) db.session.add(the_user) db.session.commit() #docassemble.webapp.daredis.clear_user_cache() flash(word("The new user has been created"), "success") return redirect(url_for('user_list')) return render_template('users/add_user_page.html', version_warning=None, bodyclass='adminbody', page_title=word('Add User'), tab_title=word('Add User'), form=add_form)
def validate(self): if self.email.data: from flask_login import current_user if current_user.social_id.startswith('phone$'): from docassemble.webapp.users.models import UserModel from flask import flash existing_user = UserModel.query.filter_by(email=self.email.data, active=True).first() if existing_user is not None and existing_user.id != current_user.id: flash(word("Please choose a different e-mail address."), 'error') return False return super(PhoneUserProfileForm, self).validate()
def delete_privilege(id): role = Role.query.filter_by(id=id).first() user_role = Role.query.filter_by(name='user').first() if role is None or role.name in ['user', 'admin', 'developer', 'advocate', 'cron']: flash(word('The role could not be deleted.'), 'error') else: for user in db.session.query(UserModel): roles_to_remove = list() for the_role in user.roles: if the_role.name == role.name: roles_to_remove.append(the_role) if len(roles_to_remove) > 0: for the_role in roles_to_remove: user.roles.remove(the_role) if len(user.roles) == 0: user.roles.append(user_role) db.session.commit() db.session.delete(role) db.session.commit() flash(word('The role ' + role.name + ' was deleted.'), 'success') return redirect(url_for('privilege_list'))
def privilege_list(): output = """\ <table class="table"> <thead> <tr> <th scope="col">""" + word("Privilege") + """</th> <th scope="col">""" + word("Action") + """</th> </tr> </thead> <tbody> """ for role in db.session.query(Role).order_by(Role.name): if role.name not in ['user', 'admin', 'developer', 'advocate', 'cron', 'trainer']: output += ' <tr><td>' + text_type(role.name) + '</td><td><a class="btn btn-danger btn-sm" href="' + url_for('delete_privilege', id=role.id) + '">Delete</a></td></tr>\n' else: output += ' <tr><td>' + text_type(role.name) + '</td><td> </td></tr>\n' output += """\ </tbody> </table> """ return render_template('users/rolelist.html', version_warning=None, bodyclass='adminbody', page_title=word('Privileges'), tab_title=word('Privileges'), privilegelist=output)
def da_unique_email_validator(form, field): if daconfig['ldap login'].get('enable', False) and daconfig['ldap login'].get('base dn', None) is not None and daconfig['ldap login'].get('bind email', None) is not None and daconfig['ldap login'].get('bind password', None) is not None: ldap_server = daconfig['ldap login'].get('server', 'localhost').strip() base_dn = daconfig['ldap login']['base dn'].strip() search_filter = daconfig['ldap login'].get('search pattern', "mail=%s") % (form.email.data,) connect = ldap.open(ldap_server) try: connect.simple_bind_s(daconfig['ldap login']['bind email'], daconfig['ldap login']['bind password']) if len(connect.search_s(base_dn, ldap.SCOPE_SUBTREE, search_filter)) > 0: raise ValidationError(word("This Email is already in use. Please try another one.")) except ldap.LDAPError: pass return unique_email_validator(form, field)
def read_fields_pdftk(pdffile): output = check_output([PDFTK_PATH, pdffile, 'dump_data_fields']).decode() fields = list() if not len(output) > 0: return None for field in yaml.load_all(output, Loader=yaml.FullLoader): if 'FieldType' in field and field['FieldType'] == 'Button': default = "No" else: default = word("something") if 'FieldName' in field: fields.append((field['FieldName'], default)) return fields
class UserAddForm(FlaskForm): email = StringField(word('E-mail'), validators=[ validators.Required(word('E-mail is required')), validators.Email(word('Invalid E-mail')) ]) first_name = StringField(word('First name'), [validators.Length(min=0, max=255)]) last_name = StringField(word('Last name'), [validators.Length(min=0, max=255)]) role_id = SelectMultipleField(word('Privileges'), coerce=int) password = StringField(word('Password'), widget=PasswordInput(hide_value=False), validators=[password_validator]) submit = SubmitField(word('Add'))
def send(self, message, envelope_from=None): assert message.send_to, "No recipients have been added" assert message.sender, ( "The message does not specify a sender and a default sender " "has not been configured") if message.has_bad_headers(): raise BadHeaderError if message.date is None: message.date = time.time() if not message.subject: message.subject = word("(no subject)") sgmessage = SGMail( from_email=Email(message.sender), to_emails=[ To(addressee) for addressee in sanitize_addresses(message.recipients) ], subject=message.subject, plain_text_content=message.body, html_content=message.html) if message.reply_to: sgmessage.reply_to = ReplyTo(message.reply_to) if message.cc: for recipient in list(sanitize_addresses(message.cc)): sgmessage.add_cc(recipient) if message.bcc: for recipient in list(sanitize_addresses(message.bcc)): sgmessage.add_bcc(recipient) if message.attachments: for flask_attachment in message.attachments: attachment = Attachment() attachment.file_content = FileContent( base64.b64encode(flask_attachment.data).decode()) attachment.file_type = FileType(flask_attachment.content_type) attachment.file_name = FileName(flask_attachment.filename) attachment.disposition = Disposition( flask_attachment.disposition) sgmessage.add_attachment(attachment) sg = SendGridAPIClient(self.mail.api_key) response = sg.send(sgmessage) if response.status_code >= 400: sys.stderr.write("SendGrid status code: " + str(response.status_code) + "\n") sys.stderr.write("SendGrid response headers: " + repr(response.headers) + "\n") try: sys.stderr.write(repr(response.body) + "\n") except: pass raise Exception("Failed to send e-mail message to SendGrid") email_dispatched.send(message, app=current_app._get_current_object())
def recursively_add_fields(fields, id_to_page, outfields): for i in fields: field = resolve1(i) name, value, rect, page, field_type = field.get('T'), field.get( 'V'), field.get('Rect'), field.get('P'), field.get('FT') if name is not None: name = str(name).decode('latin1') if value is not None: value = str(value).decode('latin1') #logmessage("name is " + str(name) + " and FT is |" + str(field_type) + "| and value is " + str(value)) if page is not None: pageno = id_to_page[page.objid] else: pageno = 1 if str(field_type) == '/Btn': if value == '/Yes': default = "Yes" else: default = "No" elif str(field_type) == '/Sig': default = '${ user.signature }' else: if value is not None: #for val in value: # logmessage("Got a " + str(ord(val))) #logmessage(repr(value.decode('utf8'))) #default = re.sub(r'^\xc3\xbe\xc3\xbf', '', value) #default = re.sub(r'^þÿ', '', value) default = value if not default: default = word("something") else: default = word("something") kids = field.get('Kids') if kids: recursively_add_fields(kids, id_to_page, outfields) else: outfields.append((name, default, pageno, rect, field_type))
def privilege_list(): output = """\ <table class="table"> <thead> <tr> <th scope="col">""" + word("Privilege") + """</th> <th scope="col">""" + word("Action") + """</th> </tr> </thead> <tbody> """ for role in db.session.query(Role).order_by(Role.name): if role.name not in [ 'user', 'admin', 'developer', 'advocate', 'cron', 'trainer' ]: output += ' <tr><td>' + str( role.name) + '</td><td><a class="btn ' + app.config[ 'BUTTON_CLASS'] + 'danger btn-sm" href="' + url_for( 'delete_privilege', id=role.id) + '">Delete</a></td></tr>\n' else: output += ' <tr><td>' + str( role.name) + '</td><td> </td></tr>\n' output += """\ </tbody> </table> """ response = make_response( render_template('users/rolelist.html', version_warning=None, bodyclass='daadminbody', page_title=word('Privileges'), tab_title=word('Privileges'), privilegelist=output), 200) response.headers[ 'Cache-Control'] = 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0' return response
def read_fields_pdftk(pdffile): output = unicode( check_output([PDFTK_PATH, pdffile, 'dump_data_fields']).decode('utf8')) fields = list() if not len(output) > 0: return None for field in yaml.load_all(output): if 'FieldType' in field and field['FieldType'] == 'Button': default = "No" else: default = word("something") if 'FieldName' in field: fields.append((field['FieldName'], default)) return fields
def validate(self): if self.email.data: from flask_login import current_user if current_user.social_id.startswith('phone$'): from docassemble.webapp.users.models import UserModel from flask import flash existing_user = db.session.execute( select(UserModel).filter_by(email=self.email.data, active=True)).scalar() if existing_user is not None and existing_user.id != current_user.id: flash(word("Please choose a different e-mail address."), 'error') return False return super().validate()
def delete_privilege(id): role = Role.query.filter_by(id=id).first() user_role = Role.query.filter_by(name='user').first() if role is None or role.name in [ 'user', 'admin', 'developer', 'advocate', 'cron' ]: flash(word('The role could not be deleted.'), 'error') else: for user in db.session.query(UserModel): roles_to_remove = list() for the_role in user.roles: if the_role.name == role.name: roles_to_remove.append(the_role) if len(roles_to_remove) > 0: for the_role in roles_to_remove: user.roles.remove(the_role) if len(user.roles) == 0: user.roles.append(user_role) db.session.commit() db.session.delete(role) db.session.commit() flash(word('The role ' + role.name + ' was deleted.'), 'success') return redirect(url_for('privilege_list'))
def read_fields_pdftk(pdffile): output = subprocess.check_output([PDFTK_PATH, pdffile, 'dump_data_fields']).decode() fields = [] if len(output) == 0: return None for field in yaml.load_all(output, Loader=yaml.FullLoader): if 'FieldType' in field and field['FieldType'] == 'Button': default = "No" else: default = word("something") if 'FieldName' in field: fields.append((field['FieldName'], default)) return fields
def delete_privilege(id): setup_translation() role = db.session.execute(select(Role).filter_by(id=id)).scalar_one() user_role = db.session.execute(select(Role).filter_by(name='user')).scalar_one() if role is None or role.name in ['user', 'admin', 'developer', 'advocate', 'cron']: flash(word('The role could not be deleted.'), 'error') else: for user in db.session.execute(select(UserModel).options(db.joinedload(UserModel.roles))).scalars(): roles_to_remove = list() for the_role in user.roles: if the_role.name == role.name: roles_to_remove.append(the_role) if len(roles_to_remove) > 0: for the_role in roles_to_remove: user.roles.remove(the_role) if len(user.roles) == 0: user.roles.append(user_role) db.session.commit() db.session.delete(role) db.session.commit() flash(word('The role ' + role.name + ' was deleted.'), 'success') #docassemble.webapp.daredis.clear_user_cache() return redirect(url_for('privilege_list'))
def add_privilege(): form = NewPrivilegeForm(request.form, obj=current_user) if request.method == 'POST' and form.validate(): for role in db.session.query(Role).order_by(Role.name): if role.name == form.name.data: flash( word( 'The privilege could not be added because it already exists.' ), 'error') return redirect(url_for('privilege_list')) db.session.add(Role(name=form.name.data)) db.session.commit() flash(word('The privilege was added.'), 'success') return redirect(url_for('privilege_list')) return render_template('users/new_role_page.html', version_warning=None, bodyclass='adminbody', page_title=word('Add Privilege'), tab_title=word('Add Privilege'), form=form)
def da_registration_restrict_validator(form, field): if len(daconfig['authorized registration domains']) == 0: return True user_email = str(form.email.data).lower().strip() for domain in daconfig['authorized registration domains']: if user_email.endswith(domain): return True errors = list(form.email.errors) errors.append( word( 'E-mail addresses with this domain are not authorized to register for accounts on this system.' )) form.email.errors = tuple(errors) return False
def validate(self): has_error = False if self.email.data: for email_address in re.split(r'[\n\r]+', self.email.data.strip()): (part_one, part_two) = email.utils.parseaddr(email_address) if part_two == '': the_errors = list(self.email.errors) the_errors.append( word("Invalid e-mail address: " + email_address)) self.email.errors = tuple(the_errors) has_error = True if has_error: return False return super().validate()
class EditUserProfileForm(UserProfileForm): email = StringField(word('E-mail'), validators=[ Email(word('Must be a valid e-mail address')), DataRequired(word('E-mail is required')) ]) role_id = SelectMultipleField(word('Privileges'), coerce=int) active = BooleanField(word('Active')) uses_mfa = BooleanField(word('Uses two-factor authentication'))
class MyRegisterForm(RegisterForm): first_name = StringField(word('First name'), [validators.Length(min=0, max=255)]) last_name = StringField(word('Last name'), [validators.Length(min=0, max=255)]) nickname = StringField(word('Nickname'), [fix_nickname]) email = StringField(word('Email'), validators=[ validators.DataRequired(word('Email is required')), validators.Email(word('Invalid Email')), da_unique_email_validator, da_registration_restrict_validator])
def user_profile_page(): setup_translation() the_tz = current_user.timezone if current_user.timezone else get_default_timezone( ) if current_user.social_id and current_user.social_id.startswith('phone$'): form = PhoneUserProfileForm(request.form, obj=current_user) else: form = UserProfileForm(request.form, obj=current_user) form.timezone.choices = [ (x, x) for x in sorted([tz for tz in pytz.all_timezones]) ] form.timezone.default = the_tz if str(form.timezone.data) == 'None' or str(form.timezone.data) == '': form.timezone.data = the_tz if request.method == 'POST' and form.validate(): if current_user.has_roles(['admin', 'developer']): form.populate_obj(current_user) else: current_user.first_name = form.first_name.data current_user.last_name = form.last_name.data if current_user.social_id and current_user.social_id.startswith( 'phone$'): current_user.email = form.email.data db.session.commit() #docassemble.webapp.daredis.clear_user_cache() flash(word('Your information was saved.'), 'success') return redirect(url_for('interview_list')) response = make_response( render_template('users/user_profile_page.html', version_warning=None, page_title=word('User Profile'), tab_title=word('User Profile'), form=form, debug=debug_status()), 200) response.headers[ 'Cache-Control'] = 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0' return response
def recursively_add_fields(fields, id_to_page, outfields): for i in fields: field = resolve1(i) name, value, rect, page, field_type = field.get('T'), field.get('V'), field.get('Rect'), field.get('P'), field.get('FT') if name is not None: name = str(name).decode('latin1') if value is not None: value = str(value).decode('latin1') #logmessage("name is " + str(name) + " and FT is |" + str(field_type) + "| and value is " + str(value)) if page is not None: pageno = id_to_page[page.objid] else: pageno = 1 if str(field_type) == '/Btn': if value == '/Yes': default = "Yes" else: default = "No" elif str(field_type) == '/Sig': default = '${ user.signature }' else: if value is not None: #for val in value: # logmessage("Got a " + str(ord(val))) #logmessage(repr(value.decode('utf8'))) #default = re.sub(r'^\xc3\xbe\xc3\xbf', '', value) default = value if not default: default = word("something") else: default = word("something") kids = field.get('Kids') if kids: recursively_add_fields(kids, id_to_page, outfields) else: outfields.append((name, default, pageno, rect, field_type))
class PhoneLoginVerifyForm(FlaskForm): phone_number = StringField(word('Phone number'), [validators.Length(min=5, max=255)]) verification_code = StringField(word('Verification code'), [validators.Length(min=daconfig['verification code digits'], max=daconfig['verification code digits'])]) submit = SubmitField(word('Verify')) def validate(self): #import redis #import docassemble.base.util from docassemble.webapp.daredis import r from docassemble.base.logger import logmessage from flask import request, abort result = True #r = redis.StrictRedis(host=docassemble.base.util.redis_server, db=0) key = 'da:failedlogin:ip:' + str(request.remote_addr) failed_attempts = r.get(key) if failed_attempts is not None and int(failed_attempts) > daconfig['attempt limit']: abort(404) verification_key = 'da:phonelogin:'******':code' verification_code = r.get(verification_key) #r.delete(verification_key) supplied_verification_code = re.sub(r'[^0-9]', '', self.verification_code.data) logmessage("Supplied code is " + str(supplied_verification_code)) if verification_code is None: logmessage("Verification code with " + str(verification_key) + " is None") result = False elif verification_code != supplied_verification_code: logmessage("Verification code with " + str(verification_key) + " which is " + str(verification_code) + " does not match supplied code, which is " + str(self.verification_code.data)) result = False else: logmessage("Code matched") if result is False: logmessage("Problem with form") r.incr(key) r.expire(key, 86400) elif failed_attempts is not None: r.delete(key) return result
def da_unique_email_validator(form, field): if daconfig['ldap login'].get('enable', False) and daconfig['ldap login'].get('base dn', None) is not None and daconfig['ldap login'].get('bind email', None) is not None and daconfig['ldap login'].get('bind password', None) is not None: ldap_server = daconfig['ldap login'].get('server', 'localhost').strip() base_dn = daconfig['ldap login']['base dn'].strip() search_filter = daconfig['ldap login'].get('search pattern', "mail=%s") % (form.email.data,) connect = ldap.initialize('ldap://' + ldap_server) try: connect.simple_bind_s(daconfig['ldap login']['bind email'], daconfig['ldap login']['bind password']) if len(connect.search_s(base_dn, ldap.SCOPE_SUBTREE, search_filter)) > 0: raise ValidationError(word("This Email is already in use. Please try another one.")) except ldap.LDAPError: pass if daconfig.get('confirm registration', False): return True return unique_email_validator(form, field)
def user_profile_page(): the_tz = (current_user.timezone if current_user.timezone else get_default_timezone()) if current_user.social_id and current_user.social_id.startswith('phone$'): form = PhoneUserProfileForm(request.form, obj=current_user) else: form = UserProfileForm(request.form, obj=current_user) form.timezone.choices = [ (x, x) for x in sorted([tz for tz in pytz.all_timezones]) ] form.timezone.default = the_tz if str(form.timezone.data) == 'None': form.timezone.data = the_tz if request.method == 'POST' and form.validate(): form.populate_obj(current_user) db.session.commit() flash(word('Your information was saved.'), 'success') return redirect(url_for('interview_list')) return render_template('users/user_profile_page.html', version_warning=None, page_title=word('User Profile'), tab_title=word('User Profile'), form=form, debug=debug_status())
def edit_user_profile_page(id): user = UserModel.query.filter_by(id=id).first() the_tz = (user.timezone if user.timezone else get_default_timezone()) if user is None: abort(404) if 'disable_mfa' in request.args and int(request.args['disable_mfa']) == 1: user.otp_secret = None db.session.commit() return redirect(url_for('edit_user_profile_page', id=id)) if 'reset_email_confirmation' in request.args and int(request.args['reset_email_confirmation']) == 1: user.confirmed_at = None db.session.commit() return redirect(url_for('edit_user_profile_page', id=id)) the_role_id = list() for role in user.roles: the_role_id.append(str(role.id)) if len(the_role_id) == 0: the_role_id = [str(Role.query.filter_by(name='user').first().id)] form = EditUserProfileForm(request.form, obj=user, role_id=the_role_id) form.role_id.choices = [(r.id, r.name) for r in db.session.query(Role).filter(Role.name != 'cron').order_by('name')] form.timezone.choices = [(x, x) for x in sorted([tz for tz in pytz.all_timezones])] form.timezone.default = the_tz if str(form.timezone.data) == 'None': form.timezone.data = the_tz if user.otp_secret is None: form.uses_mfa.data = False else: form.uses_mfa.data = True if request.method == 'POST' and form.validate(): form.populate_obj(user) roles_to_remove = list() the_role_id = list() for role in user.roles: roles_to_remove.append(role) for role in roles_to_remove: user.roles.remove(role) for role in Role.query.order_by('id'): if role.id in form.role_id.data: user.roles.append(role) the_role_id.append(role.id) db.session.commit() flash(word('The information was saved.'), 'success') return redirect(url_for('user_list')) form.role_id.default = the_role_id return render_template('users/edit_user_profile_page.html', version_warning=None, page_title=word('Edit User Profile'), tab_title=word('Edit User Profile'), form=form)
def user_profile_page(): the_tz = current_user.timezone if current_user.timezone else get_default_timezone() if current_user.social_id and current_user.social_id.startswith('phone$'): form = PhoneUserProfileForm(request.form, obj=current_user) else: form = UserProfileForm(request.form, obj=current_user) form.timezone.choices = [(x, x) for x in sorted([tz for tz in pytz.all_timezones])] form.timezone.default = the_tz if str(form.timezone.data) == 'None' or str(form.timezone.data) == '': form.timezone.data = the_tz if request.method == 'POST' and form.validate(): form.populate_obj(current_user) db.session.commit() flash(word('Your information was saved.'), 'success') return redirect(url_for('interview_list')) return render_template('users/user_profile_page.html', version_warning=None, page_title=word('User Profile'), tab_title=word('User Profile'), form=form, debug=debug_status())
def to_text(html_doc): #logmessage("Starting to_text") output = '' soup = BeautifulSoup(html_doc, 'html.parser') [ s.extract() for s in soup([ 'style', 'script', '[document]', 'head', 'title', 'audio', 'video', 'pre', 'attribution' ]) ] [s.extract() for s in soup.find_all(hidden)] [s.extract() for s in soup.find_all('div', {'class': 'dainvisible'})] [s.extract() for s in soup.select('.sr-exclude')] previous = '' for s in soup.find_all(do_show): if s.name in ['input', 'textarea', 'img'] and s.has_attr('alt'): words = s.attrs['alt'] if s.has_attr('placeholder'): words += str(", ") + s.attrs['placeholder'] else: words = s.get_text() words = re.sub(r'\n\s*', ' ', words, flags=re.DOTALL) if len(words) and re.search(r'\w *$', words, re.UNICODE): words = words + str('.') if words != previous: output += str(words) + "\n" previous = words terms = {} for s in soup.find_all('a'): if s.has_attr( 'class') and s.attrs['class'][0] == 'daterm' and s.has_attr( 'data-bs-content') and s.string is not None: terms[s.string] = s.attrs['data-bs-content'] if len(terms): output += word("Terms used in this question:") + "\n" for term, definition in terms.items(): output += str(term) + '. ' + str(definition) + '\n' output = re.sub(r'&gt;', '>', output) output = re.sub(r'&lt;', '<', output) output = re.sub(r'>', '>', output) output = re.sub(r'<', '<', output) output = re.sub(r'<[^>]+>', '', output) return output
class EditUserProfileForm(UserProfileForm): email = StringField(word('E-mail'), validators=[ Email(word('Must be a valid e-mail address')), DataRequired(word('E-mail is required')) ]) role_id = SelectMultipleField(word('Privileges'), coerce=int) active = BooleanField(word('Active')) uses_mfa = BooleanField(word('Uses two-factor authentication')) def validate(self, user_id, admin_id): rv = UserProfileForm.validate(self) if not rv: return False if current_user.id == user_id: if admin_id not in self.role_id.data: self.role_id.errors.append( word('You cannot take away your own admin privilege.')) return False return True
class LogForm(FlaskForm): filter_string = StringField(word('Filter For')) file_name = StringField(word('File Name')) submit = SubmitField(word('Apply')) clear = SubmitField(word('Clear'))
class PlaygroundUploadForm(FlaskForm): uploadfile = FileField(word('File to upload'))
class ConfigForm(FlaskForm): config_content = TextAreaField(word('Configuration YAML')) submit = SubmitField(word('Save')) cancel = SubmitField(word('Cancel'))
class UpdatePackageForm(FlaskForm): giturl = StringField(word('GitHub URL')) gitbranch = SelectField(word('GitHub Branch')) zipfile = FileField(word('Zip File')) pippackage = StringField(word('Package on PyPI')) submit = SubmitField(word('Update'))
class TrainingUploadForm(FlaskForm): usepackage = RadioField(word('Use Package')) jsonfile = FileField(word('JSON file')) importtype = RadioField(word('Import method')) submit = SubmitField(word('Import'))
def validate_package_name(form, field): if re.search('[^A-Za-z0-9]', field.data): raise ValidationError(word('Valid characters are: A-Z, a-z, 0-9'))
def user_list(): users = list() for user in db.session.query(UserModel).order_by(UserModel.id): if user.nickname == 'cron': continue role_names = [y.name for y in user.roles] if 'admin' in role_names: high_priv = 'admin' elif 'developer' in role_names: high_priv = 'developer' elif 'advocate' in role_names: high_priv = 'advocate' elif 'trainer' in role_names: high_priv = 'trainer' else: high_priv = 'user' name_string = '' if user.first_name: name_string += text_type(user.first_name) + " " if user.last_name: name_string += text_type(user.last_name) if name_string: name_string = text_type(name_string) active_string = '' if user.email is None: user_indicator = user.nickname else: user_indicator = user.email if user.active: is_active = True else: is_active = False users.append(dict(name=name_string, email=user_indicator, active=is_active, id=user.id, high_priv=high_priv)) return render_template('users/userlist.html', version_warning=None, bodyclass='adminbody', page_title=word('User List'), tab_title=word('User List'), users=users)
def validate_name(form, field): if re.search('[^A-Za-z0-9\-]', field.data): raise ValidationError(word('Valid characters are: A-Z, a-z, 0-9, hyphen'))
def validate(self): from docassemble.webapp.daredis import r from flask import request, abort key = 'da:failedlogin:ip:' + str(request.remote_addr) failed_attempts = r.get(key) if failed_attempts is not None and int(failed_attempts) > daconfig['attempt limit']: abort(404) if daconfig['ldap login'].get('enable', False): ldap_server = daconfig['ldap login'].get('server', 'localhost').strip() username = self.email.data password = self.password.data connect = ldap.open(ldap_server) try: connect.simple_bind_s(username, password) connect.unbind_s() from flask import current_app user_manager = current_app.user_manager user, user_email = user_manager.find_user_by_email(self.email.data) if not user: from docassemble.base.generate_key import random_alphanumeric from docassemble.webapp.db_object import db from docassemble.webapp.users.models import UserModel, Role while True: new_social = 'ldap$' + random_alphanumeric(32) existing_user = UserModel.query.filter_by(social_id=new_social).first() if existing_user: continue break user = UserModel(social_id=new_social, email=self.email.data, nickname='', active=True) user_role = Role.query.filter_by(name='user').first() user.roles.append(user_role) db.session.add(user) db.session.commit() result = True except ldap.LDAPError: connect.unbind_s() result = super(MySignInForm, self).validate() else: from flask import current_app user_manager = current_app.user_manager user, user_email = user_manager.find_user_by_email(self.email.data) if user is None: return False if user and (user.password is None or (user.social_id is not None and not user.social_id.startswith('local$'))): self.email.errors = list(self.email.errors) if user.social_id.startswith('google$'): self.email.errors.append(word("You need to log in with Google.")) elif user.social_id.startswith('azure$'): self.email.errors.append(word("You need to log in with Azure.")) elif user.social_id.startswith('auth0$'): self.email.errors.append(word("You need to log in with Auth0.")) elif user.social_id.startswith('twitter$'): self.email.errors.append(word("You need to log in with Twitter.")) elif user.social_id.startswith('facebook$'): self.email.errors.append(word("You need to log in with Facebook.")) else: self.email.errors.append(word("You cannot log in this way.")) return False #sys.stderr.write("Trying super validate\n") result = super(MySignInForm, self).validate() #sys.stderr.write("Super validate response was " + repr(result) + "\n") if result is False: r.incr(key) r.expire(key, daconfig['ban period']) elif failed_attempts is not None: r.delete(key) return result
def monitor_thread(sid=None, user_id=None): with app.app_context(): sys.stderr.write("Started monitor thread for " + str(sid) + " who is " + str(user_id) + "\n") if user_id is not None: person = UserModel.query.filter_by(id=user_id).first() else: person = None if person is not None and person.timezone is not None: the_timezone = pytz.timezone(person.timezone) else: the_timezone = pytz.timezone(get_default_timezone()) r = redis.StrictRedis(host=redis_host, db=0) listening_sids = set() pubsub = r.pubsub() pubsub.subscribe(['da:monitor', sid]) for item in pubsub.listen(): if item['type'] != 'message': continue #sys.stderr.write("monitor sid: " + str(sid) + ":\n") data = None try: data = json.loads(item['data']) except: sys.stderr.write(" monitor JSON parse error: " + str(item['data']) + "\n") continue if 'message' in data and data['message'] == "KILL": if item['channel'] == str(sid): sys.stderr.write(" monitor unsubscribed from all\n") pubsub.unsubscribe() for interview_sid in listening_sids: r.publish(interview_sid, json.dumps(dict(messagetype='departure', sid=sid))) break elif item['channel'] != 'da:monitor': pubsub.unsubscribe(item['channel']) if data['sid'] in listening_sids: listening_sids.remove(data['sid']) sys.stderr.write(" monitor unsubscribed from " + str(item['channel']) + "\n") continue else: sys.stderr.write(" Got something for monitor\n") if 'messagetype' in data: #if data['messagetype'] == 'abortcontroller': # socketio.emit('abortcontroller', {'key': data['key']}, namespace='/monitor', room=sid) if data['messagetype'] == 'sessionupdate': #sys.stderr.write(" Got a session update: " + str(data['session']) + "\n") #sys.stderr.write(" Got a session update\n") socketio.emit('sessionupdate', {'key': data['key'], 'session': data['session']}, namespace='/monitor', room=sid) if data['messagetype'] == 'chatready': pubsub.subscribe(data['sid']) listening_sids.add(data['sid']) secrets[data['sid']] = data['secret'] r.hset('da:monitor:chatpartners:' + str(user_id), 'da:interviewsession:uid:' + str(data['uid']) + ':i:' + str(data['i']) + ':userid:' + str(data['userid']), 1) if str(data['userid']).startswith('t'): name = word("anonymous visitor") + ' ' + str(data['userid'])[1:] else: person = UserModel.query.filter_by(id=data['userid']).first() if person.first_name: name = str(person.first_name) + ' ' + str(person.last_name) else: name = str(person.email) sys.stderr.write("chatready 1") socketio.emit('chatready', {'uid': data['uid'], 'i': data['i'], 'userid': data['userid'], 'name': name}, namespace='/monitor', room=sid) if data['messagetype'] == 'block': pubsub.unsubscribe(item['channel']) if item['channel'] in listening_sids: listening_sids.remove(item['channel']) sys.stderr.write(" monitor unsubscribed from " + str(item['channel']) + "\n") if data['messagetype'] == 'refreshsessions': socketio.emit('refreshsessions', {}, namespace='/monitor', room=sid) if data['messagetype'] == 'chat': #sys.stderr.write(" Emitting monitor chat message: " + str(data['message']['message']) + "\n") if str(user_id) == str(data['message'].get('user_id', None)): data['message']['is_self'] = True else: data['message']['is_self'] = False socketio.emit('chatmessage', {'i': data['yaml_filename'], 'uid': data['uid'], 'userid': data['user_id'], 'data': data['message']}, namespace='/monitor', room=sid) if data['messagetype'] == 'chatstop': sys.stderr.write(" Chat termination for sid " + data['sid'] + "\n") pubsub.unsubscribe(data['sid']) if data['sid'] in secrets: del secrets[data['sid']] r.hdel('da:monitor:chatpartners:' + str(user_id), 'da:interviewsession:uid:' + str(data['uid']) + ':i:' + str(data['i']) + ':userid:' + data['userid']) socketio.emit('chatstop', {'uid': data['uid'], 'i': data['i'], 'userid': data['userid']}, namespace='/monitor', room=sid) sys.stderr.write(' exiting monitor thread for sid ' + str(sid) + '\n')
def length_two(form, field): if len(field.data) != 2: raise ValidationError(word('Must be a two-letter code'))
def validate_project_name(form, field): if re.search('^[0-9]', field.data): raise ValidationError(word('Project name cannot begin with a number')) if re.search('[^A-Za-z0-9]', field.data): raise ValidationError(word('Valid characters are: A-Z, a-z, 0-9'))
class OneDriveForm(FlaskForm): folder = SelectField(word('Folder')) submit = SubmitField(word('Save')) cancel = SubmitField(word('Cancel'))
class PlaygroundFilesForm(FlaskForm): section = StringField(word('Section')) uploadfile = FileField(word('File to upload')) submit = SubmitField(word('Upload'))
def user_list(): users = list() for user in db.session.query(UserModel).order_by(UserModel.id): if user.nickname == 'cron': continue name_string = '' if user.first_name: name_string += str(user.first_name) + " " if user.last_name: name_string += str(user.last_name) if name_string: name_string = str(name_string) active_string = '' if user.email is None: user_indicator = user.nickname else: user_indicator = user.email if user.active: is_active = True else: is_active = False users.append(dict(name=name_string, email=user_indicator, active=is_active, id=user.id)) return render_template('users/userlist.html', version_warning=None, bodyclass='adminbody', page_title=word('User List'), tab_title=word('User List'), users=users)