def event_table_section(tl_or_events, who_id, django_request, show_equiptype=False, with_signup=False, with_completion_link=False, allow_editing=False): events = tl_or_events.events() if isinstance( tl_or_events, model.timeline.Timeline) else tl_or_events now = model.times.now() return (T.table(class_="timeline_table")[T.thead[T.tr[ T.th["Title"], T.th["Event type"], T.th["Start"], T.th["Location"], T.th["Hosts"], T.th["Equipment"] if show_equiptype else "", T.th["Sign up"] if with_signup else "", T.th["Record results"] if with_completion_link else ""]], T.tbody[[[ T.tr[T.th(class_="event_title")[T.a( href=event_link(ev, django_request))[ev.display_title()]], T.td(class_="event_type")[ev.event_type], T.td(class_="event_start")[model.times.timestring(ev.start)], T.td(class_="location")[ev.location], T.td(class_="hosts")[people_list(ev.hosts)], (T.td( class_="event_equipment_type" )[equip_name(ev.equipment_type)] if show_equiptype else ""), (T.td[pages.page_pieces. signup_button(ev._id, who_id, "Sign up", django_request ) if with_signup and model.times. as_utc(ev.start) > now else ""]), (T.td[T.a( href=django.urls. reverse("events:done_event", args=(ev._id, )) )["Record results"] if with_completion_link and model.times. as_utc(ev.start) < now else ""])] ] for ev in events]]])
def user_list_section(django_request, include_non_members=False, filter_fn=None, filter_opaque=None): """Return the users list, if the viewing person is allowed to see it. Otherwise, just how many people there are. The optional first argument is a flag for whether to include non-members. The optional second argument is a boolean function taking a person object, returning whether to include them in the list. This could be used for things like listing people whose fobs are ready for enabling, or who have missed paying their latest subscription. A third argument is passed through to that function.""" global serverconf if serverconf == None: serverconf = configuration.get_config()['server'] viewing_user = model.person.Person.find(django_request.user.link_id) people = person.Person.list_all_people( ) if include_non_members else person.Person.list_all_members() if filter_fn: people = [ someone for someone in people if filter_fn(someone, filter_opaque) ] people_dict = {whoever.name(): whoever for whoever in people} if viewing_user.is_auditor() or viewing_user.is_admin(): return T.table[[ T.tr[T.th(class_='mem_num')["Mem #"], T.th(class_='username')["Name"], T.th(class_='loginh')["Login"], T.th(class_='flagsh')["Flags"], T.th(class_='email')["Email"], T.th(class_='user')["User"], T.th(class_='owner')["Owner"], T.th(class_='trainer')["Trainer"], T.th(class_='note')["Notes"]] ], [ T.tr[T.td(class_='mem_num')[str(who.membership_number)], T.th(class_='username')[T.a( href=django.urls. reverse('dashboard:user_dashboard', args=( [who.link_id])))[whoname]], T.td(class_='login')[who.get_login_name() or ""], T.td(class_='flags')[flagstring(who)], T.td(class_='email')[T.a( href="mailto:" + who.get_email() or "")[who.get_email() or ""]], T.td(class_='user' )[equipment_type_role_name_list(who, 'user')], T.td(class_='owner' )[equipment_type_role_name_list(who, 'owner')], T.td(class_='trainer' )[equipment_type_role_name_list(who, 'trainer')], T.td(class_='note')[T.form()[who.get_admin_note() or ""]]] for (whoname, who) in [(key, people_dict[key]) for key in sorted(people_dict.keys())] ]] else: return T.p["There are " + str(len(people)) + (" people" if include_non_members else " members") + " in the database."]
def top_navigation(django_request): org_conf = model.configuration.get_config('organization') # todo: make this a bar of buttons, or a dropdown return [T.nav(class_='top_nav') [T.ul[T.li[T.a(href=org_conf['home_page'])[org_conf['title'] + " home"]], T.li[T.a(href=org_conf['wiki'])["Wiki"]], T.li[T.a(href=org_conf['forum'])["Forum"]], T.li[T.a(href=django.urls.reverse("dashboard:own_dashboard"))["Your dashboard"]], T.li[T.a(href='/users/logout')["Logout"]]]]] # todo: use reverse when I can find its name
def machine_section(machine, django_request): eqty = model.equipment_type.Equipment_type.find_by_id(machine.equipment_type) result = [T.p["This equipment is an instance of type ", T.a(href=django.urls.reverse("equiptypes:eqty", args=(eqty.name,)))[eqty.name], "."]] # todo: picture if available result += [pages.page_pieces.display_or_form( 'machine_details', "machine/update_details", None, ["name", "type", "description", "status", "status_detail", "location", "model", "serial_number"], None, {"name": machine.name, "type": eqty.name, "description": machine.description, "status": machine.status, "status_detail": machine.status_detail, "location": machine.location, "model": machine.model, "serial_number": machine.serial_number})] return result
def role_people(eqty, role): # todo: change this to a link to the person's page instead of their email address return T.ul[[[ T.li[T.a( href="mailto:" + who.get_email(access_permissions_role=role, access_permissions_equipment=eqty._id))[who.name( access_permissions_role=role, access_permissions_equipment=eqty._id)]] ] for who in sorted(eqty.get_people(role), key=model.person.Person.name)]]
def equipment_type_list_section(training_category): global serverconf global org_conf if serverconf == None: serverconf = configuration.get_config('server') if orgconf == None: orgconf = configuration.get_config('organization') eqtys = equipment_type.Equipment_type.list_equipment_types(training_category) print("training_category is", training_category, "and its types are", eqtys) return [T.h2[(T.a(href=orgconf['categories']+training_category.upper())[training_category.capitalize()] or "All") + " equipment types"], [T.dl[[[T.dt[T.a(href=serverconf['types']+eqty.name)[eqty.pretty_name()]], T.dd[T.dl[T.dt["Machines"], [T.ul(class_="compactlist")[[T.li[T.a(href=serverconf['machines']+m.name)[m.name]] for m in eqty.get_machines()]]], T.dt["Training requests"], T.dd[ # todo: no training requests are visible (check whether they are even created) T.ul(class_="compactlist")[[T.li[r.name()] for r in eqty.get_training_requests('user')]] ]]]] for eqty in eqtys]]]]
def logged_in_only(django_request): config_data = model.configuration.get_config() model.database.database_init(config_data) page_data = model.pages.HtmlPage( "Public information", pages.page_pieces.top_navigation(django_request), django_request=django_request) page_data.add_content("Public page", [ T. p["You are not currently logged in, which is why you are seeing the public page."], T.h2["Existing users"], T.p["Please ", T.a(href="../users/login")["login"], " for your own dashboard page."], T.h2["New users"], T. p["If an account has been created for you, and you haven't yet used it, please use the ", T.a(href="../users/password_reset")["password reset page"], " to set your initial password, then use the login page, ", T.strong[ "noting that you must enter the user-id that you are given on the password reset result page, and not your email"], "."], pages.public_page.public_page(django_request) ]) return HttpResponse(str(page_data.to_string()))
def general_equipment_list(who, viewer, these_types, django_request, detailed=False): keyed_types = {eqty.name: eqty for eqty in these_types} return T.table[T.thead[T.tr[T.th["Equipment type"], T.th["Request"], T.th["Admin action"] if viewer.is_administrator() else ""]], T.tbody[[[T.tr[T.th[T.a(href=django.urls.reverse("equiptypes:eqty", args=(name,)))[keyed_types[name].pretty_name()]], T.td[machinelist(keyed_types[name], who, django_request, False) if detailed else "", toggle_request(who, keyed_types[name]._id, 'user', who.has_requested_training(keyed_types[name]._id, 'user'), django_request)], T.td[permit_form(keyed_types[name], who._id, who.name(), 'user', django_request)] if viewer.is_administrator() else ""]] for name in sorted(keyed_types.keys())]]]
def send_password_reset(django_request): config_data = model.configuration.get_config() model.database.database_init(config_data) who = person_from_request(django_request) recipient = who.get_email() model.django_calls.send_password_reset_email(who, django_request) page_data = model.pages.HtmlPage( "Password reset confirmation", pages.page_pieces.top_navigation(django_request), django_request=django_request) page_data.add_content("Confirmation", [ T.p[("Password reset sent to " + who.name() + " <", T.a(href="mailto:" + recipient)[recipient], ">.")] ]) return HttpResponse(str(page_data.to_string()))
def one_event_section(ev, who, django_request, with_rsvp=False, rsvp_id=None, with_completion=False, completion_as_form=False, allow_editing=False): allow_editing = who.is_administrator() all_people_ids = ev.signed_up all_people_id_to_name = { p: model.person.Person.find(p).name() for p in all_people_ids } all_people_name_and_id = [(all_people_id_to_name[id], id) for id in all_people_id_to_name.keys()] ids_in_order = [] for name in sorted(all_people_id_to_name.values()): for pair in all_people_name_and_id: if name == pair[0]: ids_in_order.append(pair[1]) hosts = people_list(ev.hosts) # print("Looking for equipment type", ev.equipment_type) eqty = model.equipment_type.Equipment_type.find_by_id(ev.equipment_type) eqty_name = eqty.name if eqty else "---" results = [( T.table(class_='event_details') [T.tr[T.th(class_="ralabel")["Title"], T.td( class_="event_title" )[T.input(type='text', name='title', value=ev.display_title( )) if allow_editing else T.a( href=event_link(ev, django_request))[ev.display_title()]]], T.tr[T.th(class_="ralabel")["Event type"], T.td( class_="event_type" )[T.input(type='text', name='event_type', value=ev.event_type ) if allow_editing else ev.event_type]], T.tr[T.th(class_="ralabel")["Start time"], T.td(class_="event_start" )[T.input(type='datetime', name='start', value=model.times.timestring(ev.start) ) if allow_editing else model.times. timestring(ev.start)]], T. tr[T.th(class_="ralabel")["Duration"], T.td( class_="event_duration" )[T. input(type='text', name='duration', value=str(ev.end - ev.start) ) if allow_editing else str(ev.end - ev.start)]], T.tr[T.th(class_="ralabel")["End time"], T.td(class_="event_end")[model.times.timestring(ev.end)]], T.tr[T.th(class_="ralabel")["Location"], T.td(class_="location" )[pages.page_pieces. location_dropdown('location', ev.location ) if allow_editing else ev.location]], T.tr[T.th(class_="ralabel")["Equipment type"], T.td(class_="event_equipment_type" )[pages.page_pieces.equipment_type_dropdown( 'event_equipment_type', eqty_name ) if allow_editing else eqty_name]], # todo: linkify T.tr[T.th(class_="ralabel")["Hosts"], T.td(class_="hosts" )[T.input(type='text', name='hosts', value=hosts ) if allow_editing else hosts]], T.tr[T.th(class_="ralabel")["Event ID and link"], T.td(class_="event_id")[T.a( href=event_link(ev, django_request))[str(ev._id)]]], (T.tr[T.th(class_="ralabel")[""], T.td[T.input(type='submit', value="Update event details" )]] if allow_editing else "")])] if ev.catered: result += [T.h3["Catering information"], avoidances_subsection(ev)] if allow_editing: results = [ T.form(action=django.urls.reverse("events:update_event"), method='POST') [results, T.input(type='hidden', name='event_id', value=ev._id), T.input(type="hidden", name="csrfmiddlewaretoken", value=django.middleware.csrf.get_token(django_request))] ] if with_rsvp: results += [ T.h4["Reply to invitation"], T.form(action=django.urls.reverse("events:rsvp"), method='POST') [T.input(type='hidden', name='rsvp_id', value=rsvp_id), T.input(type="hidden", name="csrfmiddlewaretoken", value=django.middleware.csrf.get_token(django_request)), T.ul[T.li[T.input(type='radio', name='response', value='accept'), "Accept"], T.li[T.input(type='radio', name='response', value='decline'), "Decline"], T.li[T.input(type='radio', name='response', value='drop'), "Decline and cancel request"]], T.input(type='submit', value="Reply")] ] if ev.signed_up and len(ev.signed_up) > 0: results += [ T.h4["Users signed up to event"], T.ul[[[T.li[person_name(sup)] for sup in ev.signed_up]]] ] # if who._id in ev.signed_up: # pass # todo: form to back out of attending event (must rescan to mail waiting list) if with_completion: completion_table = (T.table(class_='event_completion')[T.thead[T.tr[ T.th["Name"], T.th(class_='unknown')["Unknown"], T.th(class_='no_show')["No-show"], T.th(class_='failed')["Failed"], T.th(class_='passed')["Passed"]]], T.tbody[[[ T.tr[T.th[all_people_id_to_name[id]], (T.td( class_='unknown')[result_button(id, "unknown", ( id not in ev.noshow and id not in ev.failed and id not in ev.passed))]), (T.td(class_='no_show' )[result_button(id, "noshow", id in ev.noshow)]), (T.td(class_='failed' )[result_button(id, "failed", id in ev.failed)]), (T.td(class_='passed' )[result_button(id, "passed", id in ev.passed)])] for id in ids_in_order ]]], (T.tfoot[T.tr[ T.td(colspan="2")[""], T.td( colspan="3")[T.input(type='submit', value="Record results" )]]] if completion_as_form else "")]) # todo: signup if in the future results += [ T.h4["Results"], ((T.form(action=django.urls.reverse("events:results"), method="POST") [T.input(type="hidden", name='event_id', value=ev._id), T.input(type="hidden", name="csrfmiddlewaretoken", value=django.middleware.csrf.get_token(django_request)), completion_table]) if completion_as_form else completion_table) ] return [ T.h3[ev.title.replace('_', ' ').capitalize() if ev.title else "Event"], results ]
def section_link(section, name, presentation): return T.a(href=django.urls.reverse(section, args=[name]))[presentation]
def page_string(page_title, content, user=None, initial_tab=None, needs_jquery=False): """Make up a complete page as a string.""" conf = configuration.get_config() page_conf = conf['page'] org_conf = conf['organization'] preamble = page_conf.get('preamble', '') script_file = page_conf['script_file'] script_body = "" if os.path.exists(script_file): with open(script_file) as mfile: script_body = mfile.read() script_text = """<script type="text/javascript">""" + script_body + """</script>\n""" if needs_jquery: script_text += """<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>\n""" motd = "" motd_file = page_conf['motd_file'] if os.path.exists(motd_file): with open(motd_file) as mfile: motd = mfile.read() stylesheet_name = page_conf['stylesheet'] if user and user.stylesheet: user_stylesheet_name = os.path.join(os.path.dirname(stylesheet_name), user.stylesheet + ".css") if os.path.exists(user_stylesheet_name): stylesheet_name = user_stylesheet_name if os.path.exists(stylesheet_name): inline = page_conf['style_inline'] if inline: with open(stylesheet_name) as sf: style_text = '<style type="text/css">' + sf.read() + '</style>' else: style_text = '<link rel="stylesheet" type="text/css" href="' + stylesheet_name + '">' # todo: put the motd into the preamble postamble = page_conf.get('postamble', '') final_setup = """<script type="text/javascript">selectTab('""" + initial_tab + """')</script>""" if initial_tab else "" page_heading = page_title logo = page_conf.get('heading_logo', None) if logo: logo_height = int(page_conf.get('logo_height', "32")) page_heading = T.span[ page_heading, T.a(href=org_conf['home_page'])[T.img(align="right", alt=org_conf['title'], height=logo_height, src=logo)]] footer = T.footer[ T.hr, T.p(class_="the_small_print") ["Produced by the ", T.a(href="https://github.com/hillwithsmallfields/makers/")["makers"], " system. ", "We use ", T.a(href="https://www.djangoproject.com/")["django"], " to handle login and sessions, and that uses a ", T. a(href= "https://docs.djangoproject.com/en/2.1/topics/http/sessions/#using-cookie-based-sessions" )["session cookie"], " and a ", T.a(href="https://docs.djangoproject.com/en/2.1/ref/csrf/" )["CSRF protection cookie"], ". ", "We don't use any other cookies that we are aware of, and we neither sell your data nor give it away."]] return RawHtmlPage( page_title, untemplate.HTML5Doc([ untemplate.safe_unicode(style_text + script_text + preamble), T.body[T.h1[page_heading], content, footer], untemplate.safe_unicode(postamble), untemplate.safe_unicode(final_setup) ], head=T.head[T.title[page_title]])).to_string()
def equipment_type_section(eqty, viewing_user, django_request): """Return a pre-HTML structure describing an equipment type.""" conf = model.configuration.get_config() result = [] if eqty.picture: result += [T.img(src=eqty.picture, align="right")] result += [ pages.page_pieces.display_or_form( 'equipment_type_details', django.urls.reverse('equiptypes:update_details'), None, ['category', 'description', 'manufacturer'], None, { 'category': (eqty.training_category, conf['organization']['categories'] + eqty.training_category), 'description': eqty.description, 'manufacturer': eqty.manufacturer }) ] result += [ T.h3["Machines"], [ pages.page_pieces.machinelist(eqty, viewing_user, django_request, viewing_user.is_owner(eqty)) ] ] if not viewing_user.is_trained(eqty): result += [ T.h3["User training"], pages.event_page.event_table_section( eqty.get_training_events('user', earliest=model.times.now()), viewing_user._id, django_request) ] else: if not viewing_user.is_owner(eqty): result += [ T.h3["Owner training"], pages.event_page.event_table_section( eqty.get_training_events('owner', earliest=model.times.now()), viewing_user._id, django_request) ] if not viewing_user.is_trainer(eqty): result += [ T.h3["Trainer training"], pages.event_page.event_table_section( eqty.get_training_events('trainer', earliest=model.times.now()), viewing_user._id, django_request) ] roles = [] if viewing_user.is_trainer(eqty): result += [ T.h3["Training requests"], pages.page_pieces.eqty_training_requests(eqty, django_request) ] roles += [("Owners", 'owner'), ("Trainers", 'trainer')] if (viewing_user.is_administrator() or viewing_user.is_auditor() or viewing_user.is_owner(eqty) or viewing_user.is_trainer(eqty)): roles.append(("Users", 'user')) result += [[ T.h3[T.a(href=("mailto:" + eqty.name + "_" + role + "s@" + conf['server']['mailhost']))[role_heading]], [role_people(eqty, role)] ] for role_heading, role in roles] return result