--- /dev/null
+# Badges
+
+Other than skinning the website itself, creation of "skinned badges"
+is also possible. Unlike the website, if there is no skin created, no
+badges can be created (it is of course still possible to download a
+CSV list of all registrations and create them separately).
+
+To create badges, use the [Attendee reports](reports#attendee) page.
+
+**Always** create a filter that includes "Payment confirmed". Without
+this, badges would be created for attendees who have not paid. The
+"Payment confirmed" field will be set automatically even for
+registrations that don't need payment, as soon as they are confirmed.
+
+Select output format "badge", and decide if you want borders and/or
+page breaks included, depending on printing requirements and the badge
+design itself.
+
+It doesn't matter which fields are included, as the badge template
+will always have access to all badges.
+
+### Incremental printing
+
+If badges need to be printed incrementally (for example if most badges
+have been printed but late registrations have to be printed as a
+separate batch), use the date filter functionality on *payment
+confirmed*. If the last batch was printed on 2017-10-20 for example,
+enter ">2017-10-20" in the filter field.
+
+For easier validation, generate a normal report with this filter
+first, and change the output format to *Badges* when ready.
--- /dev/null
+# Call for Papers
+
+## Running a call for papers
+
+Running a call for papers consists of a few clearly separated steps:
+
+### 1. Collecting proposals
+
+To start collecting proposals, enable the call for papers on the
+[conference](configuring). As soon as this is done, speakers can start
+submitting entries. Before doing that, make sure you configure the
+introductory text (if you want one), and decide if you want to ask for
+skill levels.
+
+If you want to ask for Tracks in the call for papers, make sure you
+[create them](schedule#tracks) create them first, and flag them as "in
+cfp". If no tracks with "in cfp" set exists, the track field will
+automatically be excluded from the call for papers form.
+
+Each speaker has to set up a speaker profile. This profile is shared
+between all the conferences on the system, so if they have already set
+one up, then they can just re-use the one they already have.
+
+### 2. Voting
+
+Voting is done by everybody who is listed as a talk voter in the
+conference configuration, by using the "view sessions and vote" page.
+
+Each person can give a score, 1-9 with 9 being the best, to a talk to
+rate it. If the score is left at 0 that means "no vote", it does *not*
+mean "really bad".
+
+Normally each person is not allowed to vote for any talks they
+submitted themselves, and need to exercise restraint when voting for
+colleagues. However, those rules are not in any way enforced in the
+system, but are handled manually by the people on the committee.
+
+Each voter can leave a comment for each talk in the text field, and
+view each others comment. All voting is open to all members of the
+committee.
+
+Click the talk title to view full details about the talk.
+
+Click the status to bring up a dialog allowing the change of status.
+
+Sessions can be sorted by session name (default), speakers or average
+score by clicking the appropriate headlines.
+
+### 3. Deciding and notifying speakers
+
+Once the voting is done, the decisions can be made and the speakers be
+notified. As this process starts, each session pass through a number
+of [states](#states), where each level can generate an email. These
+emails are always just flagged and not sent until explicitly
+requested. That way it's possible to perform extra review.
+
+A state of a session can be changed either from the voting page (by
+clicking the current state and picking a new one) or from the Edit
+Session page (by picking a new state in the drop down). In either case
+the new state is limited by valid state transitions. By repeating this
+process it is possible to "break the rules" and bypass states, but
+this should of course never be done. After having edited a session
+state, be sure not to forget to trigger the emails!
+
+Once a session has entered the *approved* state, it will show up in
+the list of sessions, if that is enabled for the
+[conference](configuring).
+
+See below for a diagram of how a session moves through the different
+states. Most of these steps are fully automatic by changing the
+state. The *exception* to consider here is the **reserve list**!
+
+To put a session on the reserve list, the process is:
+
+1. Contact the speaker manually via email to confirm that they are
+willing to be on the reserve list, knowing what it means.
+1. Change the state to Reserve
+1. Trigger the email
+
+## Session states <a name="states"></a>
+
+During call for paper handling, a session moves between different
+states. Some of these movements are initiated by the user (such as
+submitting or confirming a talk), some are initiated by the admin
+using the backend interfaces.
+
+Whenever a session state is changed, an email may be triggered. These
+emails are *not* sent by default. Instead, they are placed in a queue,
+and this queue can be reviewed and emptied using the button that
+appears on the main administration page when the queue has some
+contents. This is so that it can be verified that incorrect state
+change emails are not sent out in the middle of processing multiple
+talks as part of a call for papers.
+
+### Session state flow
+
+
+
+
+## Slides <a name="slides"></a>
+
+The call for papers system has a built-in functionality to handle
+uploading of slides from speakers, or linking to them.
+
+Once a talk is in the [state](#states) *Accepted* it will be possible
+for the speaker to return to the page for it and either upload slides
+or add links to slides that are hosted elsewhere (such as on their
+personal website or on a slide-hosting service). Once uploaded these
+slides will be available from the public page of the session, and
+possibly also indicated in the session list and on the schedule
+(depending on the templates used).
+
+Uploaded slides are restricted to PDF format.
--- /dev/null
+# Configuring a conference
+
+This documentation page covers how to configure an existing
+conference. For information about how a superuser can create a
+completely new conference, see the [separate page](super_conference#new).
+
+### Base configuring
+
+There are a few base configuration steps to always perform.
+
+Set the maximum number of attendees before the [waitlist](waitlist)
+activates. This should always be set to a few below venue capacity, to
+make sure a multireg doesn't "break the bank".
+
+Configure the automatic cancellation of invoices that are old past a
+certain time. As the conference approaches, this number should be
+decreased. The risk of keeping it too high is that people create an
+invoice, which then "blocks" a seat at the conference, without paying
+it. During that time, it's unknown if they will actually attend, so
+seats cannot be given to others.
+
+Once the autocancel time is decreased below a certain threshold, some
+payment methods that don't complete immediately (notably things like
+IBAN bank transfers) will automatically become unavailable to the attendees.
+
+
+Decide if you want a welcome email to be sent to all attendees when
+their registration is fully completed (payment confirmed), which is
+normally recommended. If you do, of course also set the text of that
+email. The email will be sent from the address configured as the
+contact address by the [superuser](super_conference).
+
+If needed, add a text added as a prefix before the
+[additional options](registrations) listing on the registration form.
+
+### Registration fields
+
+Configure which additional fields should be included on the
+registration form, such as Twitter name or Dietary needs (see
+[below](#conferenceform) for reference). This should always be done
+before the first registration is allowed, to make sure the same data
+exists on all attendees.
+
+### Workflow steps
+
+You can separately enable each of the different user workflow steps
+for [registration](registration), [call for papers](callforpapers),
+[call for sponsors](sponsors), [schedule](schedule) and
+[feedback](feedback). Make sure you don't enable any steps until the
+organisation is ready for it.
+
+### Call for papers
+
+Decide if you want skill level prompts in the
+[call for papers](callforpapers) and visible in the
+[schedule](schedule), and set the intro text used on the
+[call for papers](callforpapers).
+
+### Roles
+
+There are four types of roles that can be configured at the level of
+conference.
+
+Testers are users that can bypass the restrictions on which parts of
+the workflow are open, e.g. they can perform a registration even if
+registrations are closed. The idea is that this can be used for
+example to test skinning functions, and to validate the setup of
+things like [registration types](registrations).
+
+Talkvoters are users that can vote on talks in the
+[call for papers](callforpapers).
+
+Staff are users who are allowed to [register](registrations) with a
+registration that requires staff (basically intended for free or
+discounted registrations). This is assigned to users *before* they
+register, to gain access to this registration type.
+
+Volunteers are *registered* users who can participate in the
+[volunteer schedule](volunteers). Note that this requires the users to
+actually be registered for the conference in order to be
+selected. This is a separate flag instead of a registration type so
+that it's easy to for example have attendees who are both speakers and
+on the volunteer schedule. If volunteers should get free entry as
+well, that is typically handled either with a
+[registration type](registrations) that requires manual validation, or
+with a custom [voucher or discount code](vouchers).
+
+The final role that exists in a conference is an administrator. This
+can only be assigned by a [superuser](super_conference).
+
+## Reference
+
+### Conference details <a name="conferenceform"></a>
+
+The form to edit a conference has the following fields:
+
+Attendees before waitlist
+: Number of confirmed attendees before the [waitlist](waitlist) is
+activated. This should be below the venue maximum *with some margin*,
+as the number of attendees can "jump" with either bulk registrations
+or parallel registration processes by multiple users.
+
+Autocancel invoices
+: Invoices are automatically canceled if not paid after this many
+hours. Should always be set to ensure there are no "dangling invoices"
+from people who are not completing their registration, making it
+impossible to know if they will use their seat or not. Typically
+starts out as a high value that is decreased as either the conference
+draws closer or it starts approaching sold out.
+
+Send welcome mail
+: Should an email be sent to the attendee confirming that they have
+completed their registration.
+
+Welcome email contents
+: Contents of said welcome email
+
+Additionalintro
+: Text shown on the registration page just above the list of
+additional options. Typically introduces what the additional options
+are. Can contain markdown.
+
+Field t-shirt
+: Should the field asking for t-shirt size be displayed on
+registration form. Only used if t-shirts are given out.
+
+Field dietary
+: Should the field asking for dietary needs be displayed on the
+registration form. Only used if catering is provided.
+
+Field nick
+: Should the field asking for nickname be displayed on the
+registration form.
+
+Field twitter name
+: Should the field asking for twitter name be displayed on the
+registration form.
+
+Field share email
+: Should the field asking to share email address with sponsors be
+displayed on the registration form.
+
+Field photo consent
+: Should the field asking the attendee to give (or not) consent to
+have their photograph taken at the event.
+
+
+Registration open
+: If regular registration is open.
+
+Allow editing registrations
+: If a user is allowed to edit an existing registration. Only some
+limited fields can be edited, things like t-shirt size and dietary
+needs. This is typically turned off once the final list of such
+information has to be locked in with a venue, or when badges are
+printed (in case some of this information is used on the badges).
+
+Call for papers open
+: If the call for papers is open
+
+Call for sponsors open
+: If the call for sponsors is open
+
+Schedule publishing active
+: If the schedule is published, including times, and rooms.
+
+Session publishing active
+: If the session publishing is active, which just lists the sessions
+and their details, typically used before the schedule is done but
+talks are being approved.
+
+Conference feedback open
+: If registered attendees of the conference can leave
+[feedback](feedback) on the full conference.
+
+Session feedback open
+: If registered attendees of the conference can leave
+[feedback](feedback) on individual sessions.
+
+Skill levels
+: Should the [call for papers](callforpapers) ask for skill levels on
+all sessions, and should they be displayed on the schedule and session
+lists.
+
+Callforpapersintro
+: Text shown on the [call for papers](callforpapers) page, above the
+actual call for papers. Can contain HTML.
+
+Testers
+: List of users who are assigned as testers of the conference. These
+users can bypass the restrictions above and make registrations and
+submissions even when they are closed, etc. This can be both
+registered users and not registered users.
+
+Talkvoters
+: List of users who can vote in the
+[call for papers](callforpapers). This can be both registered users
+and not registered users.
+
+Staff
+: List of users who can register as staff using the special
+[registration type](registrations). This is typically users who have
+not registered when they are added, since they will later use the
+staff registration to become registered.
+
+Volunteers
+: List of registered users who participate in the
+[volunteer schedule](volunteers). This must be registered users.
+
+Width of HTML schedule
+: Width in pixels of the built-in HTML schedule. This only controls
+the "old style" HTML schedule, which is normally overridden by the
+conference templates in which case this has no effect.
+
+Vertical pixels per minute
+: Number of pixels to assign to each minute on the Y axis when
+generating the "old style" HTML schedule.
+
--- /dev/null
+# Copying data from another conference
+
+Most of the conference metadata can be copied over from another
+conference. Normally this would be from another conference in the same
+series, but it can be from any conference at all.
+
+When copying from another conference, the process is:
+
+1. Enter the administration dashboard for the *receiving* conference.
+1. Click the button for the type of object being copied, such as
+ "tracks".
+1. Click "Copy *object* from other events"
+1. Select the conference to copy from. The drop down will allow for any
+ conference the user is an administrator of, or for superuser any
+ conference at all.
+1. In the list of objects, mark those objects that should be
+ copied. Use the checkbox in the top right corner of the table to
+ select *all* objects.
+1. Fill out any transforms if there are any
+1. Click "Copy *objects*"
+1. If a transform was available and used, check the box to confirm
+ that the transform example looks correct, and click "Copy
+ *objects*" again.
+
+## Transforms
+
+Some objects allow for transformation during copy. In particular,
+objects that include timestamps (*sessions*, *schedule slots* and
+*volunteer slots*) allows a transform that adds a fixed number of
+"days hours:minutes:seconds" to be added to all times, both start and
+end times.
+
--- /dev/null
+# Emails
+
+## Attendee emails
+
+Using the *Attendee emails* functionality it is possible to send email
+to all attendees, or those of a specific
+[registration class](registrations#typesandclasses). Emails sent using
+this function will both be sent as an email to the attendee *and*
+listed on the registration dashboard for those that have
+registered. This means that attendees who sign up *after* the email is
+sent will **also** be able to view the emails.
+
+From
+: The *from* address of the email will always be the
+[main contact address](super_conference) for the conference.
+
+Regclasses
+: Select the registration classes that the email should be delivered to,
+and visible for on the registration dashboard.
+
+Subject
+: The subject of the email
+
+Message
+: The message body. No formatting is done, so make sure you put
+reasonable linebreaks in, and don't use markdown.
+
+Emails can (obviously) not be edited after they've been sent.
+
+## Cross conference email <a name="crossconference"></a>
+
+Cross conference emails are currently only available to superusers,m
+due to the inability to limit sender address.
+
+Cross conference emails are different from attendee emails in that
+they are a one-off sending of email. They are not stored server-side
+anywhere, and are not viewable in the system after they've been sent
+(even for administrators).
+
+Multiple criteria can be set for each email, both including and
+excluding. Include criteria are applied first, and then exclude
+criteria, so exclude ones take precedence.
+
+First pick the conference, and then either the
+[registration class](registrations#typesandclasses) or
+[speaker state](callforpaper#states). This can be done for both
+include and exclude.
+
+To add multiple either include or exclude filters, click the *+*
+button. To remove an existing filter, click the *-* button.
+
+Then fill out the actual email fields:
+
+Senderaddr
+: Email-address used to send the email. Be careful about what is used
+here, should always be one where the sending server sets proper DKIM.
+
+Sendername
+: Name of the sender (typically the conference series name, if sent
+to a complete conference series).
+
+Subject
+: The subject of the email (!)
+
+Text
+: The body of the email. No formatting is done, so take care with
+linebreaks!
+
+Before the email is actually sent a list of recipients will be shown
+at the bottom of the form and a confirm box will appear to confirm
+sending to all attendees.
+
+All emails will automatically get a footer that says where it was sent
+from and that also includes an opt-out link.
+
+
+### Opt-out <a name="optout"></a>
+
+Each email sent using this functionality will include a link to
+opt-out. Opt-out is tracked both at the global (instance) level, and
+at the *conference series* level. It is not possible to opt out from a
+single conference, but it is possible to opt out either on the full
+series or for *all* series.
+
+Note that even if users have opted out from the series, they will
+still be sent attendee emails for the conference and any emails
+concerning payments.
--- /dev/null
+# Feedback
+
+The feedback systems consists of [session feedback](#session) and
+[conference feedback](#conference). They can be independently enabled
+in the [configuration](configuring), and some events will only use
+some of them.
+
+## Session feedback <a name="session"></a>
+
+When enabled, feedback is collected on each session. A fixed set of
+fields are collected for each session -- rankings from 1-5 on topic
+importance, content quality, speaker knowledge and speaker
+quality. Other than this it also collects a set of free text comments
+that are visible only to the organisers, and a set of free text
+comments that are visible only to the speaker.
+
+Feedback is enabled for an individual session once the start time for
+the session has passed. That way the list of sessions with feedback
+available becomes incrementally available as the conference goes on.
+
+Each speaker can view their own feedback through the call for papers
+page.
+
+Administrators can view the collected feedback across all sessions on
+the admin page.
+
+### Toplists
+
+On the administrators page to view feedback there are also toplists
+with the highest scoring talks and speakers in each category. Be
+careful with the information on these lists, particularly in sharing
+it, so that people understand what it means. In particular, if there
+are multiple speakers on a talk, they share the score for both talk
+*and* speaker, which can give very surprising results if the same
+speaker also has their own talk.
+
+## Conference feedback <a name="conference"></a>
+
+The conference feedback contains one set of questions that is answered
+once by each (potential) attendee. The set of questions is dynamic and
+are created by entering a number of *feedback questions*. For each
+question, the following fields are available:
+
+Question
+: The actual question
+
+Isfreetext
+: If the response to the question is textual. If this box is not
+checked, the question will be a rating from 1-5.
+
+Textchoices
+: If the response is freetext per above, this field can contain a set
+of options separated by semicolons. If it does, the form will contain
+a list of options. If the field is freetext and has nothing in the
+textchoices field, a regular textbox is used.
+
+Sortkey
+: An integer representing the sort order of this field. Lower numbers
+sort earlier.
+
+Newfieldset
+: If specified, this question will create a new fieldset (section) on
+the form, and the string in this field will be used as the title. If
+left empty, this field will belong to the same fieldset as the
+previous (per sortkey) field.
-all: talk_states.svg
+all: talk_states.svg regular_reg.svg waitlist.svg
-talk_states.svg: talk_states.dot
- dot -Tsvg talk_states.dot > talk_states.svg
+%.svg: %.dot
+ dot -Tsvg $< > $@
--- /dev/null
+digraph registration {
+ rankdir="LR";
+
+ start[shape=circle label=Start];
+
+ saved[shape=box label=Saved];
+ invoice[shape=box label="Invoice generated"];
+ paid[shape=box label="Invoice paid"];
+ done[shape=box label=Completed];
+
+ start -> saved [label = "Details saved"];
+ saved -> invoice [label = "Invoice generated"];
+ invoice -> paid [label = "Payment"];
+ paid -> done;
+
+ saved -> saved [label = "Edit" ];
+ invoice -> saved [label = "Invoice expired or canceled"];
+ saved -> done [label = "No payment required"];
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.38.0 (20140413.2041)
+ -->
+<!-- Title: registration Pages: 1 -->
+<svg width="877pt" height="93pt"
+ viewBox="0.00 0.00 876.60 93.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 89)">
+<title>registration</title>
+<polygon fill="white" stroke="none" points="-4,4 -4,-89 872.595,-89 872.595,4 -4,4"/>
+<!-- start -->
+<g id="node1" class="node"><title>start</title>
+<ellipse fill="none" stroke="black" cx="27.2976" cy="-34" rx="27.0966" ry="27.0966"/>
+<text text-anchor="middle" x="27.2976" y="-30.3" font-family="Times,serif" font-size="14.00">Start</text>
+</g>
+<!-- saved -->
+<g id="node2" class="node"><title>saved</title>
+<polygon fill="none" stroke="black" points="217.595,-52 163.595,-52 163.595,-16 217.595,-16 217.595,-52"/>
+<text text-anchor="middle" x="190.595" y="-30.3" font-family="Times,serif" font-size="14.00">Saved</text>
+</g>
+<!-- start->saved -->
+<g id="edge1" class="edge"><title>start->saved</title>
+<path fill="none" stroke="black" d="M54.9326,-34C81.8265,-34 123.551,-34 153.426,-34"/>
+<polygon fill="black" stroke="black" points="153.456,-37.5001 163.456,-34 153.456,-30.5001 153.456,-37.5001"/>
+<text text-anchor="middle" x="109.095" y="-37.8" font-family="Times,serif" font-size="14.00">Details saved</text>
+</g>
+<!-- saved->saved -->
+<g id="edge5" class="edge"><title>saved->saved</title>
+<path fill="none" stroke="black" d="M176.122,-52.1527C173.896,-61.5391 178.72,-70 190.595,-70 197.831,-70 202.45,-66.8581 204.449,-62.2796"/>
+<polygon fill="black" stroke="black" points="207.952,-62.3475 205.068,-52.1527 200.965,-61.9208 207.952,-62.3475"/>
+<text text-anchor="middle" x="190.595" y="-73.8" font-family="Times,serif" font-size="14.00">Edit</text>
+</g>
+<!-- invoice -->
+<g id="node3" class="node"><title>invoice</title>
+<polygon fill="none" stroke="black" points="517.595,-65 404.595,-65 404.595,-29 517.595,-29 517.595,-65"/>
+<text text-anchor="middle" x="461.095" y="-43.3" font-family="Times,serif" font-size="14.00">Invoice generated</text>
+</g>
+<!-- saved->invoice -->
+<g id="edge2" class="edge"><title>saved->invoice</title>
+<path fill="none" stroke="black" d="M217.709,-45.1797C223.496,-47.1792 229.671,-48.9564 235.595,-50 288.304,-59.2859 349.053,-57.7479 394.056,-54.3254"/>
+<polygon fill="black" stroke="black" points="394.591,-57.7936 404.275,-53.4956 394.024,-50.8166 394.591,-57.7936"/>
+<text text-anchor="middle" x="311.095" y="-59.8" font-family="Times,serif" font-size="14.00">Invoice generated</text>
+</g>
+<!-- done -->
+<g id="node5" class="node"><title>done</title>
+<polygon fill="none" stroke="black" points="868.595,-36 791.595,-36 791.595,-0 868.595,-0 868.595,-36"/>
+<text text-anchor="middle" x="830.095" y="-14.3" font-family="Times,serif" font-size="14.00">Completed</text>
+</g>
+<!-- saved->done -->
+<g id="edge7" class="edge"><title>saved->done</title>
+<path fill="none" stroke="black" d="M217.932,-26.3833C223.705,-25.0043 229.819,-23.7632 235.595,-23 310.071,-13.1599 329.477,-20.8437 404.595,-20 541.242,-18.4653 702.645,-18.1046 781.252,-18.0223"/>
+<polygon fill="black" stroke="black" points="781.333,-21.5223 791.329,-18.0128 781.326,-14.5223 781.333,-21.5223"/>
+<text text-anchor="middle" x="594.095" y="-21.8" font-family="Times,serif" font-size="14.00">No payment required</text>
+</g>
+<!-- invoice->saved -->
+<g id="edge6" class="edge"><title>invoice->saved</title>
+<path fill="none" stroke="black" d="M404.518,-33.5905C398.498,-32.5306 392.438,-31.6286 386.595,-31 331.552,-25.0782 267.272,-27.9448 228.009,-30.7892"/>
+<polygon fill="black" stroke="black" points="227.572,-27.3124 217.867,-31.5642 228.105,-34.292 227.572,-27.3124"/>
+<text text-anchor="middle" x="311.095" y="-34.8" font-family="Times,serif" font-size="14.00">Invoice expired or canceled</text>
+</g>
+<!-- paid -->
+<g id="node4" class="node"><title>paid</title>
+<polygon fill="none" stroke="black" points="754.595,-65 670.595,-65 670.595,-29 754.595,-29 754.595,-65"/>
+<text text-anchor="middle" x="712.595" y="-43.3" font-family="Times,serif" font-size="14.00">Invoice paid</text>
+</g>
+<!-- invoice->paid -->
+<g id="edge3" class="edge"><title>invoice->paid</title>
+<path fill="none" stroke="black" d="M517.777,-47C560.41,-47 618.757,-47 660.267,-47"/>
+<polygon fill="black" stroke="black" points="660.438,-50.5001 670.438,-47 660.438,-43.5001 660.438,-50.5001"/>
+<text text-anchor="middle" x="594.095" y="-50.8" font-family="Times,serif" font-size="14.00">Payment</text>
+</g>
+<!-- paid->done -->
+<g id="edge4" class="edge"><title>paid->done</title>
+<path fill="none" stroke="black" d="M754.641,-36.694C763.31,-34.5176 772.527,-32.2032 781.416,-29.9713"/>
+<polygon fill="black" stroke="black" points="782.42,-33.3281 791.266,-27.4982 780.715,-26.5389 782.42,-33.3281"/>
+</g>
+</g>
+</svg>
--- /dev/null
+digraph waitlist {
+ subgraph legend {
+ key[shape=box, label=<
+ <font color="blue">Actions by admin</font><br/>
+ <font color="green">Actions by attendee</font><br/>
+ >, labeljust="l"]
+ }
+
+ start[shape=circle label="Registration"];
+
+ waitlist[shape=box label="On waitlist"];
+ offer[shape=box label="Offer made"];
+ invoice[shape=box label="Invoice generated"];
+ completed[shape=box label="Registration completed"];
+ deleted[shape=triangle label="Waitlist canceled"];
+
+ start -> waitlist [label = "✉ Sign up on WL", color=green];
+ start -> deleted [label = "No interest in WL", color=green];
+
+ waitlist -> offer [label = "✉ Offer extended", color=blue];
+
+ offer -> waitlist [label = "✉ Offer expired"];
+ offer -> waitlist [label = "✉ Offer canceled", color=blue];
+ offer -> deleted [label = "Declined spot", color=green];
+ offer -> invoice [label = "Accepted spot", color=green];
+
+ invoice -> completed [label = "✉ Paid invoice", color=green];
+ invoice -> waitlist [label = "✉ Invoice expired"];
+
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.38.0 (20140413.2041)
+ -->
+<!-- Title: waitlist Pages: 1 -->
+<svg width="512pt" height="474pt"
+ viewBox="0.00 0.00 511.79 473.89" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 469.89)">
+<title>waitlist</title>
+<polygon fill="white" stroke="none" points="-4,4 -4,-469.89 507.787,-469.89 507.787,4 -4,4"/>
+<!-- key -->
+<g id="node1" class="node"><title>key</title>
+<polygon fill="none" stroke="black" points="273,-429.945 132,-429.945 132,-393.945 273,-393.945 273,-429.945"/>
+<text text-anchor="start" x="145.5" y="-415.745" font-family="Times,serif" font-size="14.00">    </text>
+<text text-anchor="start" x="161.5" y="-415.745" font-family="Times,serif" font-size="14.00" fill="blue">Actions by admin</text>
+<text text-anchor="start" x="140" y="-401.745" font-family="Times,serif" font-size="14.00">    </text>
+<text text-anchor="start" x="156" y="-401.745" font-family="Times,serif" font-size="14.00" fill="green">Actions by attendee</text>
+</g>
+<!-- start -->
+<g id="node2" class="node"><title>start</title>
+<ellipse fill="none" stroke="black" cx="344.5" cy="-411.945" rx="53.8905" ry="53.8905"/>
+<text text-anchor="middle" x="344.5" y="-408.245" font-family="Times,serif" font-size="14.00">Registration</text>
+</g>
+<!-- waitlist -->
+<g id="node3" class="node"><title>waitlist</title>
+<polygon fill="none" stroke="black" points="240,-307 163,-307 163,-271 240,-271 240,-307"/>
+<text text-anchor="middle" x="201.5" y="-285.3" font-family="Times,serif" font-size="14.00">On waitlist</text>
+</g>
+<!-- start->waitlist -->
+<g id="edge1" class="edge"><title>start->waitlist</title>
+<path fill="none" stroke="green" d="M303.854,-376.151C296.745,-370.09 289.414,-363.854 282.5,-358 265.078,-343.249 245.474,-326.787 229.916,-313.755"/>
+<polygon fill="green" stroke="green" points="232.096,-311.016 222.181,-307.281 227.602,-316.384 232.096,-311.016"/>
+<text text-anchor="middle" x="309" y="-328.8" font-family="Times,serif" font-size="14.00">✉ Sign up on WL</text>
+</g>
+<!-- deleted -->
+<g id="node7" class="node"><title>deleted</title>
+<polygon fill="none" stroke="black" points="359.5,-133 215.425,-98.5 503.575,-98.5 359.5,-133"/>
+<text text-anchor="middle" x="359.5" y="-106.3" font-family="Times,serif" font-size="14.00">Waitlist canceled</text>
+</g>
+<!-- start->deleted -->
+<g id="edge2" class="edge"><title>start->deleted</title>
+<path fill="none" stroke="green" d="M368.008,-363.225C382.303,-328.899 396.862,-281.229 391.5,-238 387.318,-204.285 377.117,-166.663 369.347,-141.18"/>
+<polygon fill="green" stroke="green" points="372.611,-139.888 366.297,-131.38 365.927,-141.969 372.611,-139.888"/>
+<text text-anchor="middle" x="442.5" y="-241.8" font-family="Times,serif" font-size="14.00">No interest in WL</text>
+</g>
+<!-- offer -->
+<g id="node4" class="node"><title>offer</title>
+<polygon fill="none" stroke="black" points="246.5,-220 166.5,-220 166.5,-184 246.5,-184 246.5,-220"/>
+<text text-anchor="middle" x="206.5" y="-198.3" font-family="Times,serif" font-size="14.00">Offer made</text>
+</g>
+<!-- waitlist->offer -->
+<g id="edge3" class="edge"><title>waitlist->offer</title>
+<path fill="none" stroke="blue" d="M162.668,-284.997C119.999,-280.159 60.3751,-267.931 83.5,-238 102.877,-212.92 122.042,-228.761 152.5,-220 153.917,-219.592 155.353,-219.174 156.801,-218.748"/>
+<polygon fill="blue" stroke="blue" points="157.891,-222.075 166.463,-215.848 155.879,-215.371 157.891,-222.075"/>
+<text text-anchor="middle" x="131.5" y="-241.8" font-family="Times,serif" font-size="14.00">✉ Offer extended</text>
+</g>
+<!-- offer->waitlist -->
+<g id="edge4" class="edge"><title>offer->waitlist</title>
+<path fill="none" stroke="black" d="M204.226,-220.061C203.553,-225.755 202.892,-232.142 202.5,-238 202.009,-245.334 201.733,-253.285 201.584,-260.643"/>
+<polygon fill="black" stroke="black" points="198.081,-260.812 201.446,-270.858 205.081,-260.907 198.081,-260.812"/>
+<text text-anchor="middle" x="246.5" y="-241.8" font-family="Times,serif" font-size="14.00">✉ Offer expired</text>
+</g>
+<!-- offer->waitlist -->
+<g id="edge5" class="edge"><title>offer->waitlist</title>
+<path fill="none" stroke="blue" d="M246.572,-211.183C274.561,-218.865 304.594,-232.312 290.5,-253 281.133,-266.749 265.463,-275.097 249.86,-280.166"/>
+<polygon fill="blue" stroke="blue" points="248.867,-276.81 240.21,-282.917 250.786,-283.541 248.867,-276.81"/>
+<text text-anchor="middle" x="340.5" y="-241.8" font-family="Times,serif" font-size="14.00">✉ Offer canceled</text>
+</g>
+<!-- invoice -->
+<g id="node5" class="node"><title>invoice</title>
+<polygon fill="none" stroke="black" points="128,-128 15,-128 15,-92 128,-92 128,-128"/>
+<text text-anchor="middle" x="71.5" y="-106.3" font-family="Times,serif" font-size="14.00">Invoice generated</text>
+</g>
+<!-- offer->invoice -->
+<g id="edge7" class="edge"><title>offer->invoice</title>
+<path fill="none" stroke="green" d="M180.79,-183.86C159.489,-169.66 129.036,-149.357 105.683,-133.789"/>
+<polygon fill="green" stroke="green" points="107.376,-130.711 97.1145,-128.076 103.494,-136.536 107.376,-130.711"/>
+<text text-anchor="middle" x="189.5" y="-154.8" font-family="Times,serif" font-size="14.00">Accepted spot</text>
+</g>
+<!-- offer->deleted -->
+<g id="edge6" class="edge"><title>offer->deleted</title>
+<path fill="none" stroke="green" d="M235.638,-183.86C260.799,-169.06 297.228,-147.63 324.07,-131.841"/>
+<polygon fill="green" stroke="green" points="325.93,-134.808 332.775,-126.721 322.381,-128.774 325.93,-134.808"/>
+<text text-anchor="middle" x="325.5" y="-154.8" font-family="Times,serif" font-size="14.00">Declined spot</text>
+</g>
+<!-- invoice->waitlist -->
+<g id="edge9" class="edge"><title>invoice->waitlist</title>
+<path fill="none" stroke="black" d="M64.7193,-128.391C54.0105,-159.118 37.8388,-222.624 73.5,-253 95.4854,-271.727 126.632,-280.506 152.696,-284.59"/>
+<polygon fill="black" stroke="black" points="152.389,-288.08 162.774,-285.98 153.346,-281.146 152.389,-288.08"/>
+<text text-anchor="middle" x="103" y="-198.3" font-family="Times,serif" font-size="14.00">✉ Invoice expired</text>
+</g>
+<!-- completed -->
+<g id="node6" class="node"><title>completed</title>
+<polygon fill="none" stroke="black" points="143,-36 0,-36 0,-0 143,-0 143,-36"/>
+<text text-anchor="middle" x="71.5" y="-14.3" font-family="Times,serif" font-size="14.00">Registration completed</text>
+</g>
+<!-- invoice->completed -->
+<g id="edge8" class="edge"><title>invoice->completed</title>
+<path fill="none" stroke="green" d="M71.5,-91.6471C71.5,-78.8228 71.5,-61.1075 71.5,-46.3815"/>
+<polygon fill="green" stroke="green" points="75.0001,-46.2996 71.5,-36.2996 68.0001,-46.2997 75.0001,-46.2996"/>
+<text text-anchor="middle" x="112.5" y="-57.8" font-family="Times,serif" font-size="14.00">✉ Paid invoice</text>
+</g>
+</g>
+</svg>
--- /dev/null
+# PostgreSQL Europe Conference Management System
+
+This is the administrative help for the PostgreSQL Europe Conference
+Management System. It is aimed at the persons administering
+conferences -- it is not for the developers of the system, or for the
+end users.
+
+At any point in the system, you can click the help link in the top
+right corner. If there is specific documentation about the part that
+you are currently working on you will be brought directly to the page
+for that. If not, you will be brought here to the index page, and can
+work from here.
+
+## Table of contents
+* Quickstart
+ * [Step by step to create a conference](stepbystep)
+* Basics
+ * [Creating new conference](super_conference#new) (superusers only)
+ * [Configuring a conference](configuring)
+ * [Conference series](series)
+* Call for papers and schedule
+ * [Call for papers](callforpapers)
+ * [Schedule](schedule)
+ * [Slides](callforpapers#slides)
+* Registrations
+ * [Registrations and registration types](registrations)
+ * [Vouchers and discount codes](vouchers)
+ * [Waitlist](waitlist)
+ * [Emails](emails)
+ * [Wiki pages](wiki)
+ * [Signups](signups)
+ * [Volunteers](volunteers)
+ * [Reports](reports)
+* Feedback
+ * [Feedback](feedback)
+* Sponsors
+ * Probably several links
+* Advanced
+ * [Access tokens](tokens)
+ * [Badges](badges)
+ * [Copying from another conference](copyfromother)
--- /dev/null
+# Personal data
+
+Personal data must, of course, be collected by the registration system
+in order to work. However, as much of that personal data is not needed
+past the end of the conference, there is functionality to purge that
+data.
+
+The data in that case is typically aggregated and anonymized in order
+to still be able to access statistical information, but without any
+chance to connect it to a person.
+
+The set of personal data being purged is:
+
+T-shirt size registrations
+: This data is aggregated so that it can be used to determine how many
+t-shirts in total of each size were selected, to use for future
+events.
+
+Phone numbers
+: This data is removed.
+
+Addresses
+: This data is removed.
+
+Dietary needs
+: This data is aggregated so that it can be used as examples for use
+with future events (for example, to provide venues with examples and
+common responses).
+
+This data is never purged automatically. Instead there is a button at
+the top of the conference administration dashboard that gets enabled
+when the conference has finished, and remains enabled until the data
+has been purged. At regular intervals an email is also sent to the
+administrators of the conference to remember to do the purging.
+
+Typically the personal data is kept around a couple of weeks after the
+conference, in case it is needed to solve any questions or discussions.
+
--- /dev/null
+# Registrations and registration types
+
+## Registrations
+
+### Regular registrations
+
+Registrations are at the core of the system. The standard workflow is
+intended to be as simple as possible for the attendee (whether it
+succeeds can always be discussed..):
+
+1. The attendee signs in to the registration form. This step requires
+ a community account, or one can be created as part of the signup
+ process.
+1. The exact fields to be filled out can be
+ [configured](configuring) configured at the conference level, for
+ example if there should be a field about t-shirt size or not.
+1. The attendee can incrementally fill out and save in between if
+ necessary. If they do that, they will at regular intervals receive
+ a reminder email from the system telling them they have a stalled
+ registration.
+1. Once ready, they click "Save and Finish". At this point they get a
+ chance to review their charges, and then proceed to actually
+ generate an invoice.
+1. Once the invoice is generated, the registration data is
+ locked. This invoice can then be paid by any of the configured
+ payment methods, normally by credit card or PayPal. If the invoice
+ is not paid within the defined [autocancel](configuring) period,
+ the invoice is automatically canceled, and the registration is
+ returned to unlocked state, and will again start receiving
+ reminders to complete it.
+1. Once the invoice is paid, a receipt is sent to the user. If a
+ welcome email is [configured](configuring) for the conference, this
+ email will be sent to the user.
+1. Certain fields are unlocked for editing again, until the *allow
+ editing* checkbox is [turned off](configuring). The registration is
+ now fully complete.
+
+
+
+### Multiple registrations
+
+The system also supports a method for registering multiple attendees
+from the same account. This can also be used for one person to make a
+registration for somebody else, the process is the same.
+
+1. The person making the registrations proceeds to the form for
+ registering for somebody else or advanced registration.
+1. For each of the attendees that should be registered, the email
+ address is added and then the registration details are filled out
+ for that attendee. Additional options can be added if necessary, as
+ well as [voucher and discount codes](vouchers). The same fields and
+ restrictions as regular registrations are used.
+1. Once all registrations have been made, the user picks *Create
+ invoice*. At this point an invoice is created for all registrations
+ that are pending under this user. This invoice is paid using the
+ same rules as all other invoices.
+1. Once this invoice is paid, all registrations are confirmed at the
+ same time. Each attendee receives the confirmation email.
+ * If a community account exists for a user registered this way,
+ this account is automatically connected by matching the email
+ address, and this user can access their registration page as
+ normal.
+ * If no account exists, the user is sent an email with a
+ token-link that allows them to connect it to a different
+ community account, regardless of email address matching. The
+ attendee can also create a new account at this point.
+
+The system for multiple payments is automatically disabled once the
+[waitlist](waitlist) is in force.
+
+### Bulk payments
+
+Bulk payments is mostly the legacy way for handling multiple
+registrations, and is not used much anymore. The reason for this is
+that it requires a somewhat awkward interaction between the users
+registering and the person paying. The steps are:
+
+1. Each user makes their own registration, completing step 1-3 in the
+ list above. It is, however, very important that they do not proceed
+ to step 4 (this is the first part that usually fails).
+1. The person paying the bill then goes into the bulk payment
+ interface, and adds each individual registration using the email
+ address (this is the second part that usually fails), and enters
+ the invoicing details.
+1. The invoice is paid.
+1. The person who set up the invoice receives the receipt, and each
+ individual attendee receives the registration confirmation.
+
+The system for bulk payments is automatically disabled once the
+[waitlist](waitlist) is in force.
+
+## Registration types and classes <a name="typesandclasses"></a>
+
+When making a registration, the attendee picks the appropriate
+[registration type}(#regtypes). There always has to be at least one registration
+type, even for the most simple conference.
+
+A registration type contains the different kinds of parameters that are per-type
+configuration and maps those to what the user picks. This include things like
+cost, ability to pick [options](#options) and so on. Typical examples
+of this is "Normal attendee", "Speaker", "Staff" etc.
+
+An *optional* object higher up in the hierarchy is a registration
+class. A registration class groups a number of registration types
+together as one group. A typical example of this is there may be both
+"Attendee" and "Training attendee" as registration type, which both
+map to "Attendee" as registration class. In this scenario, the badge
+rendering (primarily - but other templates as well) can reference the
+registration class to for example always use the same color on the
+badge and similar things.
+
+### Special registration types
+
+A registration type can be mapped to a *special registration
+type*. This sets a number of restrictions on how a registration can be
+used. The following types are currently available:
+
+Manually confirmed
+: If this is picked, the registration cannot be completed by the
+attendee. It requires the administrator to confirm it manually.
+
+Confirmed speaker
+: The attendee registering must, with the same community account, have
+a speaker profile, and have at least one talk by this speaker profile
+be in a [state](callforpapers#states) of *Accepted*. Most of the time,
+the "Confirmed or reserve speaker" should probably be used instead.
+
+Confirmed or reserve speaker
+: The attendee registering must, with the same community account, have
+a speaker profile, and have at least one talk by this speaker profile
+be in a [state](callforpapers#states) of *Accepted* or the state
+*Reserve*.. This means that speakers on the reserve list can also use
+this registration type, which is usually the choice wanted since they
+should be able to be substituted at the last moment.
+
+Confirmed staff
+: The attendee registering must use one of the community accounts that
+are listed as staff in the [conference configuration](configuring).
+
+### Registration days <a name="days"></a>
+
+Registration days are not a mandatory part of the system, but if they are used
+they are used to indicate which different days the conference runs, and can be
+used to limit certain registration types to certain days, typically used to
+render information on the badges.
+
+IN the system, registration days are simply a list of dates, that must fall
+between the [conference](configuring) start date and end date.
+
+## Additional options <a name="options"></a>
+
+Additional options represent things that can be added to a
+registration, such as training sessions, attendance to a separate
+event etc. An additional option can either be paid for, or it can be a
+free option. It is something that is normally done at registration
+time, and should not be confused with [signups](signups) which are
+normally used to handle things like signing up for a social event or a
+dinner or similar things.
+
+An additional option can be restricted so it can only be used by
+a set of specific registration types. This is typically used to handle
+things like certain discounted registration types should not get
+access to a specific additional option.
+
+The reverse is also possible, a registration type can be configured so
+that it *requires* a specific additional option. This way is typically
+used to ensure things like training discount registration only being
+available to attendees who actually purchase training.
+
+Each additional option can be associated with a
+[cost](#additionaloptions), in which case the cost
+of it will be added to the initial invoice. It will also handle the
+case when the attendee later adds an option to a registration, and
+will generate an invoice before the transaction is completed.
+
+## Transferring a registration <a name="transfer"></a>
+
+A registration can be transferred to a different person, typically
+only allowed within the same company. If this transfer should be
+associated with a cost, the payment for it has to be processed
+manually.
+
+To perform a registration transfer:
+
+1. Ensure the *new* person attending makes a registration in the
+ system, but does *not* generate an invoice. If the
+ [waitlist](waitlist) is active, the registration should also *not*
+ be signed up on the waitlist (if it is, it has to be canceled
+ first).
+2. Go to the transfer page, and pick the registrations to transfer to
+ and from.
+3. Validate the steps shown, and confirm the transfer.
+
+When transferring a registration, both the "source" and "destination"
+attendees will receive an email telling them about the transfer once
+it has been completed. An email is also sent to the conference
+organiser address.
+
+Existing invoices are re-attached to the new registrations, so after a
+transfer there will be a mismatch between what's on the invoice and
+what's in the registration, but they are both traceable to each other.
+
+## Reference
+
+### Registration types <a name="regtypes"></a>
+
+Regtype
+: Name of the registration type as shown to the user
+
+Regclass
+: Registration class that this registration belongs to. This can be left
+unspecified, but that is likely to cause issues with things like badge generation.
+
+Cost
+: The cost for registering with this type, if any. 0 if the registration is free. If
+VAT is used, the cost is specified without VAT.
+
+Active
+: Whether this registration class can be used at this point.
+
+Activeuntil
+: The use-before-date for this registration type. If left empty, the registration type
+can be used as long as it's active and registration is open.
+
+Days
+: References which days this registration type gives access to, if registration days are
+used at this conference.
+
+Sortkey
+: An integer specifying how this registration type should be sorted. Lower numbers are
+sorted first.
+
+Specialtype
+: If this registration type has special rules on it
+
+Require phone
+: If attendees registering with this registration type should be required to enter
+their phone number (typically for speakers and/or staff)
+
+Alertmessage
+: This message is shown in a pop-up window when the user tries to complete the
+registration. This is typically used for things like informing people of special
+requirements such as a student ID to access student discounts.
+
+Autocancel invoices
+: If registrations with this registration type should override the value for
+autocancel from the [conference](configuring). The lowest value of
+autocancel is always used.
+
+Requires option
+: If a specific [additional option](#options) is required to use this
+registration type. If multiple options are chosen, *any one* of those
+will be enough to allow the registration type.
+
+Upsell target
+: If it should be possible t upgrade to this registration type in
+order to add additional options. If this type is more expensive than
+the previous one the attendee has, the difference will be invoiced.
+
+### Registration classes <a name="regclasses"></a>
+
+Registration class
+: Name of the registration class
+
+Badge color
+: Background color used on badge for this registration class (assuming
+the template makes use of this).
+
+Badge foreground
+: Foreground color used on the badge for this registration class
+(assuming the template makes use of this).
+
+### Additional Options <a name="additionaloptions"></a>
+
+Name
+: Name of the additional option
+
+Cost
+: Cost of this option, if any. If VAT is used, the cost is specified
+without VAT.
+
+Maxcount
+: Maximum number of instances of this additional option that can be
+purchased in total.
+
+Public
+: If this option is available on the public registration form. If this
+box is not checked ,the option can only be added by administrators.
+
+Upsellable
+: If this option can be added to a registration after it has been
+completed.
+
+Autocancel invoices
+: If registrations with this option should override the value for
+autocancel from the [conference](configuring). The lowest value of
+autocancel is always used.
+
+Requires regtype
+: In order to add one of these options, one of the specified
+registration types must be picked. If the attendee does not have one
+of these registration types, they may be offered an upsell to a
+different registration type if that is [enabled](#regtypes).
+
+Mutually exclusive
+: This option cannot be picked at the same time as the selected other
+options. This is typically used for things like training sessions
+running at the same time. If the exclusion is specified in one
+direction between the two options, it is automatically excluding both
+directions.
--- /dev/null
+# Reports
+
+## Simple reports <a name="simple"></a>
+
+There are a number of simple reports available as direct buttons from
+the administration dashboard page.
+
+Some of them are "verification reports", such as finding people who
+have not registered or misconfigured sessions. Those reports will have
+their button highlighted if they have any data in them.
+
+## Attendee reports <a name="attendee"></a>
+
+Attendee reports allow for the creation of custom reports of almost
+anything related to attendees.
+
+For fields, pick the fields you want.
+
+For filters, check boxes for the fields that should be filtered. In
+each filter field, type what to filter for. This field can also take
+*>* and *<* to indicate that the value should be greater/smaller (for
+numbers) or after/before (for dates). For string filters, a *%filter%*
+is applied, so it matches partial filters. If a field is marked but
+nothing is entered in the search box, the filter will be checked for
+presence (meaning not null).
+
+Specify a title if you want one on the report, mainly for printing.
+
+In *Additional columns* specify extra column headers with comma
+between them. This is particularly useful if for example generating an
+attendee list to tick off people on -- make an empty column for the
+tick-mark!
+
+## Time reports <a name="time"></a>
+
+The time reports can be used to draw graphs relative to the time of
+conference for a number of things. In particular, they can be used to
+compare rates between different instances of conferences.
+
+The filter field will apply a client-side filter on the list, to limit
+the options. Note than when this is used, you probably have to select
+each conference manually (with ctrl-click) rather than select a range
+(with shift-click) as a range will usually include the values that
+have been filtered out.
--- /dev/null
+# Schedule
+
+## Scheduling
+
+Once talks have been accepted in the [call for papers](callforpapers),
+or sessions have been manually added, scheduling takes place.
+
+The following terms are in use for scheduling:
+
+Rooms
+: This represents a physical room. Two sessions cannot be schedule
+in the same room at the same time. A room is not tied to a topic in
+any way. A room may or may not be available throughout the
+conference. Rooms are typically represented by different columns in
+the schedule.
+
+Track
+: A track represents a topic of content. It is *not* tied to a
+specific room, so it's perfectly possible to have multiple sessions in
+the same track at the same time, as long as they are in different
+rooms. Tracks are typically represented by different colors on the schedule.
+
+Session slot
+: A session slot represents a start and an end time on the
+schedule. Most sessions are scheduled in a schedule slot, and it's
+what the drag-and-drop interface supports doing. However, it is
+perfectly valid and possible to manually schedule a session that does
+not conform to a schedule slot.
+
+Cross schedule sessions
+: A cross schedule session is one that is not tied to a particular
+room, but instead spans across the entire schedule. Typical examples
+of this is coffee breaks and lunch.
+
+## Building a schedule graphically
+
+Using the "create schedule" functionality a schedule can be built
+incrementally using the graphical tools. All approved sessions are
+available in a list on the right-hand side, and all rooms and schedule
+slots are available on the left.
+
+Cross schedule sessions are typically not scheduled using this tool.
+
+Drag and drop a session between locations to move it. Note that
+session length is *not* considered when doing this, so if you drag a
+session to a different length slot, it will change length!
+
+A draft can be saved at any time, and will only be visible to other
+administrators.
+
+Once done, click the link at the bottom to publish the schedule. This
+operation will show a list of exactly which changes will be
+made. Initially this will be a long list, and it's mainly useful when
+making changes to the schedule after it has been published. If the
+changes look OK, hit the confirm link to publish.
+
+The published schedule will immediately become available *if* schedule
+publishing has been activated on the [conference](configuring).
+
+## PDF Schedules
+
+Simple schedules can be built in PDF format, for printing, and usually
+gives a much nicer print-out experience than printing the one from the
+website.
+
+Schedules can be printed to include only specific [tracks](#tracks),
+[rooms](#rooms) or days. Printing can be color, in which case the
+tracks are printed in the same color as they would have on the
+website, or black and white.
+
+Printing can be done A3 or A4, portrait or landscape. It is also
+possible to stretch the schedule out over multiple pages, particularly
+useful if for example printing a full day schedule but only having
+access to an A4 printer. Print in landscape A4, and tape together to
+make for an "almost A3".
+
+## Reference
+
+### Tracks <a name="tracks"></a>
+
+Track name
+: Name of the track
+
+Sort key
+: An integer representing how to sort the track. Lower values sorts
+earlier.
+
+Color
+: Color to use on schedule (and other places) for this track
+
+Incfp
+: Whether this track should be available to choose in the
+[call for papers](callforpapers) submission form.
+
+
+### Rooms <a name="rooms"></a>
+
+Room name
+: Name of the room
+
+Sortkey
+: An integer representing how to sort the room. Lower values sorts
+earlier.
+
+### Schedule slots <a name="slots"></a>
+
+Start time
+: When this slot starts
+
+End time
+: When this slot ends
+
+### Sessions <a name="sessions"></a>
+
+The form to edit session has the following fields:
+
+Title
+: The title of the session
+
+Speaker
+: One or more speakers. A speaker must have created a speaker
+profile before it can be used here, but it the same speaker
+profile can be used across multiple conferences.
+
+Status
+: The [state](callforpapers#states) state of this session.
+
+Starttime
+: If the session is scheduled, the starting date and time.
+
+Endtime
+: If the session is scheduled, the ending date and time.
+
+Cross schedule
+: If this session should be displayed across the schedule, instead
+of in one room. Typically used for things like breaks and lunch.
+
+Track
+: The track selected for this schedule, if any.
+
+Room
+: The room selected for this schedule, if any.
+
+Abstract
+: This is the abstract that is listed on the schedule and session
+description pages. Any text here is public.
+
+Submission notes
+: These are notes given by the submitter in the call for papers
+form, that are only visible to the conference organisers.
--- /dev/null
+# Conference series
+
+A conference series represents a set of "the same" conference that
+runs across multiple instances. For example, "PGConf.EU" is a series
+and "PGConf.EU 2018" is an instance.
+
+Conference series are primarily used for the
+[e-mail opt-out](emails#optout) functionality.
--- /dev/null
+# Signups
+
+Signups are a way to have attendees sign up for specific events, such
+as a social event, directly from the registration page. For events
+that have attendee limits it supports setting such, as well as a last
+time to complete the signup.
+
+### Fields
+
+Author
+: The author of the signup. Only visible in the administrative
+interface.
+
+Title
+: Title of the signup
+
+Intro
+: Text describing the signup (basically the contents of the page). Can
+use markdown.
+
+Deadline
+: Timestamp for the last moment to sign up, or to change the signup.
+
+Maxsignups
+: Maximum number of attendees who can sign up.
+
+Options
+: A list of comma separated options to show for the signup. If no
+options are given, the options "Yes" and "No" will be shown. This is
+typically used for e.g. a dinner invitation and then with options
+"Yes", "Yes with a plus one" and "No".
+
+Optionvalues
+: By default, whatever is picked as an option counts the same, and the
+summary will show a count for each value. If a set of values is
+entered in this field, the number of values must be exactly the same
+as the number of options. If this is done, the results are still shown
+tabulated per option but there is *also* a total count shown where the
+values are weighed. This can for example be used in the dinner example
+above by assigning the weights "1,2,0" in which case the total value
+will then represent the total number of people going.
+
+Public
+: If checked, this signup is available to all *registered*
+attendees. A public signup cannot track "Awaiting response".
+
+Visible
+: If checked, then any attendee who has permissions on the signup
+(through it being public, or explicitly listed) can also see who else
+signed up.
+
+Available to registration types
+: For non-public signups, attendees of these registration types can
+sign up.
+
+Available to attendees
+: For non-public signups, these specific attendees (in addition to
+those of the permitted registration types) can sign up
+
+## Sending email
+
+Using the send email functionality, it is possible to send an email to
+attendees for a signup. This is a one-time email that goes to their
+mailbox but is *not* visible on the registration page after the fact
+(unlike regular [attendee emails](emails)).
+
+For each email a subject and a body can be specified (no formatting is
+done, so make sure to put reasonable linebreaks in place, and don't
+use markdown).
+
+The recipients can be picked to be all, all who have responded
+(regardless of which response), all who have not responded (to send
+reminders), and individually for each response. If emails should be
+sent to attendees with more than one response, the form has to be
+executed multiple time, once for each response.
+
+The emails will be sent from the main conference
+[contact address](super_conference).
+
+## Results
+
+The results will have a summary with how many attendees have picked
+each specific option, as well as the total value calculated from
+weighted values. Below it there will also be a complete list of every
+individual response.
--- /dev/null
+# Step by step to create a new conference
+
+The following is not an exhaustive list, but hopefully enough to get
+off the ground.
+
+1. Create a new [conference](super_conference) (must be done by a
+ superuser).
+1. Configure all the metadata on the [conference](configuring).
+1. Set up call for papers
+ 1. Add one or more [tracks](schedule#tracks), and decide if they
+ should be included in the call for papers.
+ 1. Call for papers can now be opened
+1. Set up for registrations
+ 1. Add one or more [registration days](registrations#days) that
+ can be connected to the registration types.
+ 1. Add one or more
+ [registration classes](registrations#typesandclasses).
+ 1. Add one or more
+ [registration types](registrations#typesandclasses).
+ 1. If used, add one or more
+ [additional options](registrations#additionaloptions).
+ 1. Registration can now be opened
+1. Set up schedule
+ 1. Wait for the call for papers to finish.
+ 1. [Vote](callforpapers) on talks.
+ 1. [Decide](callforpapers) on talks and
+ [notify speakers](callforpapers).
+ 1. Add one or more [rooms](schedule#rooms).
+ 1. Add one or more [schedule slots](schedule).
+ 1. Create a tentative [schedule](schedule) and publish it.
--- /dev/null
+# Editing superuser parameters
+
+This documentation page covers how to edit the superuser only parameters
+for a conference, including [creating a new conference](#new). For
+information about how to edit the regular parameters for a conference, see
+the [separate page](configuring).
+
+## Creating a new conference
+
+To create a new conference, select the *Create new conference* button
+on the conference administration homepage. This is only available to
+superuser, since it allows referencing things like local paths on the
+server.
+
+Fill out all the fields as you normally would when editing the
+conference, per the [reference](#conferenceform).
+
+Note that an accounting object will be automatically created for a new
+conference with the same name as the conference urlname, if it does
+not already exist. This can be changed later by editing the conference
+if necessary. This accounting object is set to *active* by default.
+
+If the conference is held in a VAT jurisdiction that has never been
+used before, the VAT rates have to be registered in the accounting
+system *before* the new conference is created, and picked on
+creation. This can be delayed (by picking no VAT), but it's very
+important that it's properly configured before the first invoices are
+generated.
+
+## Reference
+
+### Superuser conference form <a name="conferenceform"></a>
+
+The form to edit superuser parameters has the following fields:
+
+Conference name
+: The display name of the conference. Can change without invalidating
+any data.
+
+URL name
+: The name used to form the url of the conference. As this field is also
+used to key urls and a number of other things, it is **strongly recommended**
+to never change this for a conference once it's been set up.
+
+Series
+: The conference series this conference belongs to
+
+Start date
+: The start date of the conference
+
+End date
+: The end date of the conference
+
+Location
+: The physical location (e.g. City, Country) of the conference
+
+Timediff
+: The number of hours away from the system standard time this conference
+is. Used for schedule rendering and ical.
+
+Contact address
+: Email address to contact the conference organisers on. This address is
+also used to send emails from. The server with the system installed on should
+preferably have DKIM set up for this domain.
+
+Sponsor address
+: Email address to contact conference organisers on about sponsorship. This
+address is also used to send emails from. The server with the system installed on
+should preferably have DKIM set up for this domain.
+
+Conference URL
+: URL to the conference homepage
+
+Administrators
+: The people who should have full administrative permissions on this conference.
+Those people can then use the regular conference configuration form to set all
+other parameters for the conference.
+
+Jinja directory
+: The directory where the Jinja templates for the conference are located on
+the server, if any. If no Jinja directory is specified, all conference pages will
+be rendered in the default templates. If an invalid directory is specified, all
+conference pages will generate an error.
+
+Accounting object
+: The accounting object that should be assigned to all invoices for this conference
+
+VAT rate for registrations
+: The VAT rate (if any) to apply to all invoices for registrations
+
+VAT rate for sponsorship
+: The VAT rate (if any) to apply to all invoices for sponsorship
--- /dev/null
+# Access tokens
+
+Access tokens are created tokens that enable "secret URLs" with access
+to specific information from the conference.
+
+This can for example be live-pulling data into a Google spreadsheet,
+or consuming it from a JavaScript based schedule webpage, or any
+other interesting ideas people can come up with.
+
+The idea between the specific access token objects is that each
+individual service that uses this should be given a separate
+token. This way it becomes possible to revoke a token for just one
+such consumer without shutting down all the others.
+
+### Reference
+
+The access token objects have the following fields:
+
+Token
+: This is the secret URL token. It's automatically filled with random
+data when a new token is created, and it cannot be changed.
+
+Description
+: Internal description. This is not used by the system anywhere, it's
+just for administrators to know what is what.
+
+Permissions
+: This list the different kinds of access that can be retrieved using
+this token. For each access type it will also have a csv (comma
+separated) and tsv (tab separated) values link that includes the
+token. (More formats may be added in the future).
+
--- /dev/null
+# Volunteer schedule
+
+The volunteer schedule system ties together attendees with
+[volunteer slots](#slots).
+
+To begin, create the slots as needed in the administrative interface,
+and assign the volunteers using the
+[conference configuration](configuring). Volunteers can also be added
+later on, in which case they will just have to sign up for what's
+left.
+
+Once all slots are available, ask the volunteers to sign up. Anybody
+added as a volunteer in the conference configuration will get a link
+to the volunteer schedule on their registration page (once
+registration is completed).
+
+### Normal workflow
+
+Normally, each volunteer signs up for the slot(s) they are interested
+in working on. Once this is done, the administrator can either *confirm*
+or *delete* the volunteer for this specific slot.
+
+### Admin-driven workflow
+
+The other way to add volunteers is to have the administrator add them
+from the admin interface. In this case the assignment *also* becomes
+unconfirmed, and now requires the volunteer to confirm it from *their*
+registration page.
+
+
+## Volunteer slots <a name="slots"></a>
+
+Volunteer slots represents a task that need to be handled at a
+specific time and place.
+
+Timerange
+: Represents the start and end time of this volunteer slot
+
+Title
+: Name of the work. This can be e.g. "Registration desk" or "Room
+host in room B"
+
+Min staff
+: The minimum number of people needed for this task
+
+Max staff
+: The maximum number of people needed for this task
+
+
--- /dev/null
+# Vouchers and discount codes
+
+Vouchers and discount codes are two different ways to make
+registrations cheaper or free for attendees. These can both be for
+marketing purposes from the conference, as sponsor benefits, or as
+almost anything.
+
+## Prepaid vouchers
+
+Prepaid vouchers are used to cover an entire registration. They are
+locked to one specific registration type. The voucher code is sent to
+the attendee, and the attendee performs their own registration and
+puts this secret key in the voucher field, which makes the
+registration free.
+
+If all that's wanted is to register for another user, it's better to
+use the [advanced registration flow](registrations). Vouchers are
+appropriate if the vouchers are distributed to a different
+organisation, and where the person paying does not have access to the
+information about the attendee.
+
+When creating vouchers, a *prepaid batch* is created, which contains a
+certain number of vouchers. The batch is paid, and the usage of
+vouchers can be tracked at this level.
+
+## Discount codes
+
+Discount codes are used to give a discount on a registration, but not
+a free one. They can either be percentage based (in which case it can
+either be a percentage of the registration cost alone, or a percentage
+of the registration cost together with any additional options
+selected) or a fixed amount.
+
+When making a registration, discount codes are added to the same field
+as voucher code, meaning the same registration cannot use both a
+voucher and a discount code at the same time.
+
+Discount codes can be limited to only be available for certain
+registration types, or to require certain additional option (e.g. "you
+get 20% off the main registration if you sign up for training
+X"). They can have a maximum number of uses, and a final date on which
+they can be used (e.g. the typical EARLYBIRD use).
+
+## Reference
+
+### Discount codes <a name="discountcodes"></a>
+
+Code
+: This is the actual code that should be entered.
+
+Discountpercentage
+: The percent discount that this code gives. Can't be specified at
+the same time as discountamount.
+
+Regonly
+: The percent applies only to the registration, not the full cost
+including additional options (only available if the type of
+discount code is percentage)
+
+Discountamount
+: The amount of discount this code gives. Can't be specified at the
+same time as discountpercentage.
+
+Validuntil
+: The date until which this code can be used.
+
+Maxuses
+: Maximum number of uses of this code.
+
+Requiresregtype
+: In order to use this discount code, one of the selected registration
+types must be used.
+
+Requiresoption
+: In order to use this discount code, one of the selected additional
+options have to be added to the registration.
+
--- /dev/null
+# Waitlist management
+
+The waitlist is enabled automatically when the number of *confirmed*
+attendees to the conference exceeds the number of attendees
+[configured](configuring) for it. There is no way to manually enable
+the waitlist, other than to reduce the number of attendees before
+waitlist to a number below the current amount.
+
+Once this is hit, every attendee who wants to sign up will be offered to
+sign up on the waitlist. If they want to do that, they will be added
+to the waitlist with an empty status, and an email is sent to the
+administrators.
+
+One or more attendees can be given an *offer* from the waitlist. This
+offer is given an expiry time, giving the chance to sign up before
+that time. The length of the offer is usually adapted to how much time
+is left until the conference -- to make sure that if the attendee
+doesn't take the offer, there is enough time to give it to somebody
+else. The system does *not* take things like office hours into account
+when calculating the offer time, that has to be done manually.
+
+Offers should always be given from the top of the waitlist. This will
+make sure that those who signed up early gets a chance first. The
+exception to this may be when different types of registrations can
+have different limits -- for example, a training attendee might get
+priority.
+
+When the offer is extended to a attendee, they will be sent an email and
+can complete the registration. If they complete it, they become a
+registered attendee like any other with no difference. If they decline
+it, or if the timer expires, their registration is returned back to
+the waitlist. If this happens it will go back to the *bottom* of the
+waitlist, and any other attendees on the waitlist will get another
+chance.
+
+The values at the top of the waitlist dashboard that are most useful
+when managing the waitlist are:
+
+
+Pending registrations with (invoice/bulk payment)
+: Number of attendees that are far enough into the process to have an
+invoice or a bulk payment generated. These can usually be expected to
+complete their payments and take their spot.
+
+Active offers on the waitlist
+: Number of attendees that have been given an offer, but have not
+completed it yet. This includes both those that have generated an
+invoice and those that have not.
+
+Total registrations including offered and invoiced
+: If all active offers are taken and completed, this is the number of
+attendees it will result in. This is typically the number to work off
+-- as long as this number is lower than the venue capacity, more
+offers can be given.
+
+## Waitlist workflow
+
+
--- /dev/null
+# Wiki pages
+
+The registration system comes with a very simple wiki system for
+editing pages. It comes with a permissions system that makes it
+possible to use this system to publish text pages that are supposed to
+be viewable only by attendees (by restricting who can edit the page),
+or act as a "true wiki" to let attendees edit the pages. No pages can
+ever be viewed by users who are not confirmed attendees of the conference.
+
+Attendees can never create new pages, they must always be created by
+an administrator. But once created, attendees can edit them, if
+permissions allow.
+
+In the admin interface, the following fields can be set:
+
+url
+: This is the URL name of the page, *not* the complete URL. It can
+only contain alpha-numerical, underscore and dash. Unlike many other
+wikis, this is *not* derived from the page title.
+
+Title
+: This is the title of the page, used in page listings and in the
+title of the page itself. Can contain (almost) any characters.
+
+Author
+: Each page has an author that is the *registration* of the creator of
+the page. This is never shown to attendees, only administrator
+(however, mind that any *editing* of the page will show up).
+
+Contents
+: The initial contents of the page. Markdown is supported. Note that
+pages should normally *not* be edited here once they have been
+created, because that will edit the last revision *without* creating a
+new revision! Instead, edit the pages through the user interface,
+reached from the link *regular editor* above the form.
+
+Public view
+: If all *registered* attendees can view this page (fully public to
+non-registered attendees not supported).
+
+Public edit
+: If all *registered* attendees can edit this page.
+
+History
+: If attendees that have permissions to view the page (through it
+being public or through explicit permissions) can view the history of
+changes on the page, including who made them and the viewing of a
+diff.
+
+Viewer registration types
+: Registrations types that can view this page (if it is not public),
+for example if a page should be restricted to speakers.
+
+Editor registration types
+: Registration types that can *edit* this page (if it is not public).
+
+Viewer attendees
+: Specific attendees that can view this page (if it is not public
+*and* they are not registered using a registration type that provides
+access)
+
+Editor attendees
+: Specific attendees that can *edit* this page.
+
+## Wiki page subscriptions
+
+From the user interface, it is possible to *subscribe* to a wiki
+page. If this is done, the attendee will get an email on any changes
+made in the *user interface*. Changes made through the admin interface
+do *not* trigger emails.
+
+## Wiki page notifications
+
+New wiki pages and edits *in the backend system* will generate an
+email to the conference contact address (but not to regular attendees,
+subscribed or not).
div.backendform_checkbox ul {
list-style-type: none;
}
+
+div.backenddocs dd {
+ margin-left: 2em;
+}
linked_objects = {}
auto_cascade_delete_to = []
fieldsets = []
+ helplink = None
def __init__(self, conference, *args, **kwargs):
self.conference = conference
return self[name]
class BackendConferenceForm(BackendForm):
+ helplink = 'configuring#conferenceform'
class Meta:
model = Conference
fields = ['active', 'callforpapersopen', 'callforsponsorsopen', 'feedbackopen',
]
class BackendSuperConferenceForm(BackendForm):
+ helplink = 'super_conference#conferenceform'
class Meta:
model = Conference
fields = ['conferencename', 'urlname', 'series', 'startdate', 'enddate', 'location',
class BackendConferenceSeriesForm(BackendForm):
+ helplink = "series"
list_fields = ['name', ]
class Meta:
model = ConferenceSeries
fields = ['name', ]
class BackendRegistrationForm(BackendForm):
+ helplink = "registrations"
class Meta:
model = ConferenceRegistration
fields = ['firstname', 'lastname', 'company', 'address', 'country', 'phone', 'shirtsize', 'dietary', 'twittername', 'nick', 'shareemail']
self.update_protected_fields()
class BackendRegistrationClassForm(BackendForm):
+ helplink = 'registrations#regclasses'
list_fields = ['regclass', 'badgecolor', 'badgeforegroundcolor']
allow_copy_previous = True
class Meta:
badgeforegroundcolor=source.badgeforegroundcolor).save()
class BackendRegistrationTypeForm(BackendForm):
+ helplink = 'registrations#regtypes'
list_fields = ['regtype', 'regclass', 'cost', 'active', 'sortkey']
vat_fields = {'cost': 'reg'}
allow_copy_previous = True
source.regclass.regclass, source.regtype)
class BackendRegistrationDayForm(BackendForm):
+ helplink = 'registrations#days'
list_fields = [ 'day', ]
class Meta:
model = RegistrationDay
fields = ['day', ]
class BackendAdditionalOptionForm(BackendForm):
+ helplink = 'registrations#additionaloptions'
list_fields = ['name', 'cost', 'maxcount', ]
vat_fields = {'cost': 'reg'}
auto_cascade_delete_to = ['registrationtype_requires_option', 'conferenceadditionaloption_requires_regtype',
self.fields['mutually_exclusive'].queryset = ConferenceAdditionalOption.objects.filter(conference=self.conference).exclude(pk=self.instance.pk)
class BackendTrackForm(BackendForm):
+ helplink = 'schedule#tracks'
list_fields = ['trackname', 'sortkey']
allow_copy_previous = True
class Meta:
).save()
class BackendRoomForm(BackendForm):
+ helplink = 'schedule#rooms'
list_fields = ['roomname', 'sortkey']
class Meta:
model = Room
class BackendConferenceSessionForm(BackendForm):
+ helplink = 'schedule#sessions'
list_fields = [ 'title', 'speaker_list', 'status_string', 'starttime', 'track', 'room']
verbose_field_names = {
'speaker_list': 'Speakers',
return None
class BackendConferenceSessionSlotForm(BackendForm):
+ helplink = 'schedule#slots'
list_fields = [ 'starttime', 'endtime', ]
allow_copy_previous = True
copy_transform_form = BackendTransformConferenceDateTimeForm
class BackendVolunteerSlotForm(BackendForm):
+ helplink = 'volunteers#slots'
list_fields = [ 'timerange', 'title', 'min_staff', 'max_staff' ]
allow_copy_previous = True
copy_transform_form = BackendTransformConferenceDateTimeForm
)
class BackendFeedbackQuestionForm(BackendForm):
+ helplink = 'feedback#conference'
list_fields = ['newfieldset', 'question', 'sortkey',]
allow_copy_previous = True
class BackendNewDiscountCodeForm(django.forms.Form):
+ helplink='vouchers#discountcodes'
codetype = django.forms.ChoiceField(choices=((1, 'Fixed amount discount'), (2, 'Percentage discount')))
def get_newform_data(self):
return self.cleaned_data['codetype']
class BackendDiscountCodeForm(BackendForm):
+ helplink='vouchers#discountcodes'
list_fields = ['code', 'validuntil', 'maxuses']
form_before_new = BackendNewDiscountCodeForm
class BackendAccessTokenForm(BackendForm):
+ helplink = 'tokens'
list_fields = ['token', 'description', 'permissions', ]
readonly_fields = ['token', ]
'form': newform,
'what': 'New {0}'.format(formclass.Meta.model._meta.verbose_name),
'cancelurl': cancel_url,
+ 'helplink': newform.helplink,
'breadcrumbs': breadcrumbs,
})
instance = instancemaker()
'what': formclass.Meta.model._meta.verbose_name,
'cancelurl': cancel_url,
'breadcrumbs': breadcrumbs,
+ 'helplink': form.helplink,
'allow_delete': allow_delete and instance.pk,
'adminurl': adminurl,
'linked': [(url, handler, handler.get_list(form.instance)) for url, handler in form.linked_objects.items() if form.instance],
'savebutton': 'Copy',
'cancelurl': '../',
'breadcrumbs': [('../', formclass.Meta.model._meta.verbose_name_plural.capitalize()), ],
+ 'helplink': formclass.helplink,
})
elif len(restpieces) == 2:
idlist = None
('../../', formclass.Meta.model._meta.verbose_name_plural.capitalize()),
('../', 'Copy {0}'.format(formclass.Meta.model._meta.verbose_name_plural.capitalize())),
],
+ 'helplink': formclass.helplink,
})
'allow_delete': allow_delete,
'allow_copy_previous': formclass.allow_copy_previous,
'breadcrumbs': breadcrumbs,
+ 'helplink': formclass.helplink,
})
if allow_new and resturl=='new':
return render(request, 'confreg/admin_purge_personal_data.html', {
'conference': conference,
+ 'helplink': 'personaldata',
'counts': exec_to_dict("""SELECT
count(1) FILTER (WHERE shirtsize_id IS NOT NULL) AS "T-shirt size registrations",
count(1) FILTER (WHERE dietary IS NOT NULL AND dietary != '') AS "Dietary needs",
--- /dev/null
+from django.shortcuts import render
+from django.http import HttpResponseForbidden, Http404
+
+import codecs
+import os
+import re
+import markdown
+
+from models import Conference
+from backendviews import get_authenticated_conference
+
+reTitle = re.compile('<h1>([^<]+)</h1>')
+
+_reSvgInline = re.compile('<img alt="([^"]+)" src="([^"]+)\.svg" />')
+def _replaceSvgInline(m):
+ # Group 1 = alt text
+ # Group 2 = filename excluding svg
+ filename = 'docs/confreg/{0}.svg'.format(m.group(2))
+ if not os.path.isfile(filename):
+ return m.group(0)
+
+ with codecs.open(filename, 'r', 'utf8') as f:
+ return f.read()
+
+def docspage(request, urlname, page):
+ if urlname:
+ conference = get_authenticated_conference(request, urlname.rstrip('/'))
+ else:
+ # Allow a person who has *any* permissions on a conference to read the docs,
+ # because, well, they are docs.
+ if not request.user.is_superuser:
+ if not Conference.objects.filter(administrators=request.user).exists():
+ return HttpResponseForbidden("Access denied")
+ conference = None
+
+ if page:
+ page = page.rstrip('/')
+ urlpage = page
+ else:
+ page = "index"
+ urlpage = ''
+
+ # Do we have the actual docs file?
+ # It's safe to just put the filename in here, because the regexp in urls.py ensures
+ # that we can not get into a path traversal case.
+ filename = 'docs/confreg/{0}.md'.format(page)
+ if not os.path.isfile(filename):
+ raise Http404()
+
+ with open(filename) as f:
+ md = markdown.Markdown(extensions=['markdown.extensions.def_list'])
+ contents = md.convert(f.read())
+ contents = _reSvgInline.sub(lambda m: _replaceSvgInline(m), contents)
+
+ # Find the title
+ m = reTitle.search(contents)
+ if m:
+ title = m.group(1)
+ else:
+ title = 'PostgreSQL Europe Conference Administration'
+
+ return render(request, 'confreg/admin_backend_docpage.html', {
+ 'conference': conference,
+ 'page': page,
+ 'contents': contents,
+ 'title': title,
+ 'urlpage': urlpage,
+ })
return render(request, 'confreg/admin_conference_feedback.html', {
'conference': conference,
'feedback': sections,
+ 'helplink': 'feedback',
})
'minvotes': minvotes,
'commented_sessions': commented_sessions,
'breadcrumbs': (('/events/admin/{0}/reports/feedback/'.format(conference.urlname), 'Feedback'), ),
+ 'helplink': 'feedback',
})
return render(request, 'confreg/pdfschedule.html', {
'conference': conference,
'form': form,
+ 'helplink': 'schedule#pdf',
})
'maxpred': report.maxpred,
'trendlines': report.does_trendlines and trendlines or '',
'trendlines_supported': report.does_trendlines,
+ 'helplink': 'reports#time',
})
except ReportException, e:
messages.error(request, e)
return render(request, 'confreg/timereport.html', {
'form': form,
+ 'helplink': 'reports#time',
})
--- /dev/null
+from django.template.defaultfilters import stringfilter
+from django import template
+
+register = template.Library()
+
+@register.filter(name='docslink')
+@stringfilter
+def docslink(value):
+ if '#' in value:
+ return '{0}/#{1}'.format(*value.split('#'))
+ return value + '/'
return render(request, 'confreg/prepaid_list.html', {
'conference': conference,
'batches': batches,
+ 'helplink': 'vouchers',
})
def viewvouchers(request, confname, batchid):
'vouchers': vouchers,
'vouchermailtext': vouchermailtext,
'breadcrumbs': (('/events/admin/{0}/prepaid/list/'.format(conference.urlname), 'Prepaid vouchers'),),
+ 'helplink': 'vouchers',
})
@transaction.atomic
'conference': conference,
'isadmin': isadmin,
'status_choices': STATUS_CHOICES,
+ 'helplink': 'callforpapers',
})
@login_required
'tracks': tracks,
'sesswidth': min(600 / len(allrooms), 150),
'availableheight': len(sessions)*75,
+ 'helplink': 'schedule',
})
@login_required
'additionaloptions': conference.conferenceadditionaloption_set.all(),
'adv_fields': attendee_report_fields,
'adv_filters': attendee_report_filters(conference),
+ 'helplink': 'reports#attendee',
})
'conference': conference,
'columns': [dd for dd in collist if not dd.startswith('_')],
'data': d,
+ 'helplink': 'reports',
})
@login_required
return render(request, 'confreg/admin_registration_dashboard.html', {
'conference': conference,
'tables': tables,
+ 'helplink': 'registrations',
})
def admin_registration_list(request, urlname):
'regs': ConferenceRegistration.objects.select_related('regtype').select_related('registrationwaitlistentry').filter(conference=conference).order_by((revsort and '-' or '') + sortmap[skey], '-created'),
'regsummary': exec_to_dict("SELECT count(1) FILTER (WHERE payconfirmedat IS NOT NULL) AS confirmed, count(1) FILTER (WHERE payconfirmedat IS NULL) AS unconfirmed FROM confreg_conferenceregistration WHERE conference_id=%(confid)s", {'confid': conference.id})[0],
'breadcrumbs': (('/events/admin/{0}/regdashboard/'.format(urlname), 'Registration dashboard'),),
+ 'helplink': 'registrations',
})
def admin_registration_single(request, urlname, regid):
('/events/admin/{0}/regdashboard/'.format(urlname), 'Registration dashboard'),
('/events/admin/{0}/regdashboard/list/'.format(urlname), 'Registration list'),
),
+ 'helplink': 'registrations',
})
@transaction.atomic
return render(request, 'confreg/admin_registration_cancel.html', {
'conference': conference,
'reg': reg,
+ 'helplink': 'waitlist',
})
@transaction.atomic
if conference.attendees_before_waitlist <= 0:
return render(request, 'confreg/admin_waitlist_inactive.html', {
'conference': conference,
+ 'helplink': 'waitlist',
})
num_confirmedregs = ConferenceRegistration.objects.filter(conference=conference, payconfirmedat__isnull=False).count()
'waitlist': waitlist,
'waitlist_cleared': waitlist_cleared,
'form': form,
+ 'helplink': 'waitlist',
})
@transaction.atomic
'conference': conference,
'mails': mails,
'form': form,
+ 'helplink': 'emails',
})
def admin_attendeemail_view(request, urlname, mailid):
'conference': conference,
'mail': mail,
'breadcrumbs': (('/events/admin/{0}/mail/'.format(conference.urlname), 'Attendee emails'), ),
+ 'helplink': 'emails',
})
@transaction.atomic
'form': form,
'steps': steps,
'stephash': stephash,
+ 'helplink': 'registrations#transfer',
})
'form': form,
'recipients': recipients,
'conferences': Conference.objects.all(),
+ 'helplink': 'emails#crossconference',
})
return render(request, 'confwiki/admin.html', {
'conference': conference,
'pages': pages,
+ 'helplink': 'wiki',
})
@transaction.atomic
'form': form,
'page': page,
'breadcrumbs': (('/events/admin/{0}/wiki/'.format(conference.urlname), 'Wiki'),),
+ 'helplink': 'wiki',
})
return render(request, 'confwiki/signup_admin.html', {
'conference': conference,
'signups': signups,
+ 'helplink': 'signups',
})
@transaction.atomic
'signup': signup,
'results': results,
'breadcrumbs': (('/events/admin/{0}/signups/'.format(conference.urlname), 'Signups'),),
+ 'helplink': 'signups',
})
('/events/admin/{0}/signups/'.format(conference.urlname), 'Signups'),
('/events/admin/{0}/signups/{1}/'.format(conference.urlname, signup.id), signup.title),
),
+ 'helplink': 'signups',
})
import postgresqleu.confreg.feedback
import postgresqleu.confreg.pdfschedule
import postgresqleu.confreg.volsched
+import postgresqleu.confreg.docsviews
import postgresqleu.confwiki.views
import postgresqleu.membership.views
import postgresqleu.elections.views
url(r'^events/admin/crossmail/$', postgresqleu.confreg.views.crossmail),
url(r'^events/admin/crossmail/options/$', postgresqleu.confreg.views.crossmailoptions),
url(r'^events/admin/reports/time/$', postgresqleu.confreg.reporting.timereport),
+ url(r'^events/admin/(?P<urlname>[^/]+/)?docs/(?P<page>\w+/)?$', postgresqleu.confreg.docsviews.docspage),
url(r'^events/admin/([^/]+)/reports/$', postgresqleu.confreg.views.reports),
url(r'^events/admin/([^/]+)/reports/simple/$', postgresqleu.confreg.views.simple_report),
url(r'^events/admin/([^/]+)/reports/advanced/$', postgresqleu.confreg.views.advanced_report),
--- /dev/null
+{%extends "confreg/confadmin_base.html"%}
+{%block title%}{{title}}{%endblock%}
+{%block extrahead%}
+<base href="/events/admin/{%if conference and conference.urlname%}{{conference.urlname}}/{%endif%}docs/{%if urlpage%}{{urlpage}}{%endif%}">
+{%endblock%}
+{%block layoutblock%}
+<div class="backenddocs">
+{{contents|safe}}
+</div>
+{%endblock%}
{%load alertmap%}
+{%load docslink%}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en" dir="ltr">
<li><a href="{{k}}">{{v}}</a></li>
{%endfor%}
</ul>
+ <ul class="nav navbar-nav navbar-right">
+ <li><a href="/events/admin/{%if conference and conference.urlname%}{{conference.urlname}}/{%endif%}docs/{%if helplink%}{{helplink|docslink}}{%endif%}">Help</a></li>
+ </ul>
</div>
</div>
</nav>