Welcome to the LNL Database’s documentation!

The LNL Database is your connection to everything LNL! Sometimes referred to as the LNLDB, this portion of the Lens and Lights website is available to all WPI community members.

What's New?


Check Website Status

See also

Have any questions, comments, or suggestions to share with us? Join the discussion on GitHub!

Table of Contents

Getting Started

To get started visit our website at lnl.wpi.edu and click My Account in the top right corner. Next select Sign in with Microsoft and log in with your WPI Microsoft account.

Where to Find Help

If you’re struggling to find a particular page or would like to learn more about a particular feature, be sure to check out our User Guides. You can also find Help buttons located throughout the LNLDB.

See also

Something not working correctly? Let us know by submitting a bug report.

User Guides

Welcome to the LNLDB User Guides! Here you’ll find tons of helpful resources designed to help you become more familiar with our website. Select a link below to get started!

If you’ve come across an issue with our website or have suggestions for future improvements, please let us know by submitting a bug report or feature request.


Customer Resources

Booking Your Event Online (Submit a Workorder)

The workorder wizard is a fast and simple way for clients to book events through the LNLDB.

_images/top.png
Using the Workorder Wizard

To access the Workorder Wizard, visit our website and click Workorder in the top right corner.

1. You’ll need to be logged in before you can access the Workorder Wizard. If you do not currently have an active session, you’ll be redirected to our login page automatically. If this is your first time using our website, select Sign in with Microsoft then proceed to login with your WPI Microsoft credentials.

Note

If you are not currently a member of the WPI community, contact us and we’ll set up an account for you!


2. Next you’ll be presented with two options: Create a lighting, sound, or power work order or Create a projection work order. Select the option that is most applicable for your event.

Hint

Only select Create a projection work order if your event will take place in Fuller Upper. Select the option to Create a lighting, sound, or power work order for outdoor projection events.


3. On the “Client” page, enter the name of your organization or department into the search field, then select the corresponding option from the search results. If your organization is not listed, you will first need to Create a New Organization through the LNLDB. Once you’ve selected your organization or department, the Workorder Wizard will remember your selection for future visits.

_images/client.png

4. On the “Event Details” page, enter a name for your event, a location (if applicable) and a short description. You’ll also need to provide scheduling details such as when your event will need to be set up by, when it will start, and when it will end.

_images/details.png

5. The next step will break down each of our services into categories and provide a short description explaining what each service will offer. As you select items and services to add to your event, you’ll see an itemized list detailing the services that will be added to your event and their total cost.

_images/services.png

Note

You may receive various warnings based on the combinations of services you select. These warnings are meant to help you avoid selecting services that may be incompatible with each other or your event’s location. However, if you still wish to continue, most of these warnings will not prevent you from doing so!


6. Finally, once you’re done, click Next, and you’ll be brought to the review page. If everything looks as it should, click Submit, and that’s it! Our Vice President will reach out shortly to confirm your event.

Last Modified: April 21, 2021

Create a New Organization

WPI has over 250 student-run organizations or clubs, and more are added every year! LNL provides services to all these clubs and more. In order for organizations and departments to book our services, they need to register with the LNLDB.

Creating a New Organization

To request that your organization be added to the LNLDB, follow these steps:

  • Log in with Microsoft SSO (using your WPI Microsoft account)
  • Click Clients > Request Organization

Fill out each of the fields as defined below:

  • Client Name: The name of your organization / department
  • Email: Your organization’s exec alias or the email address of a person who will be responsible for your organization / department
  • Address: Your organization’s address (off campus) or office location (on campus). If your organization has no permanent address, enter “100 Institute Road”
  • Phone: The phone number for your organization or an authoritative contact

Last Modified: April 21, 2021

Transfer Ownership of an Organization

Only the owner of an organization will have the ability to update the organization’s contact information and associated users. Therefore, when there is a change in who is primarily responsible for your organization, such as during a transition between exec boards, it is highly recommended that you transfer control of your organization over to this new individual. Who you choose to be primarily responsible for your organization is up to you.

Submit a Transfer Request
  1. Log into the LNLDB then select Clients > My Organizations from the navigation bar.
  2. In the table that appears, select your organization. Once you are on your organization’s profile page, click the green Transfer button to start a transfer request.
  3. Next, select the user you would like to transfer ownership of the organization to. This user must already be associated with the organization. Anyone who has submitted an event on behalf of the organization will have been added to this list automatically. If you need to edit the list of associated users for your organization (and you are the organization’s current owner), go back to the profile page then click the blue Edit button. Under Associated Users begin typing the name of the person you would like to add, then select the corresponding entry from the drop down menu as it appears. Click Save Changes then return to your transfer request.
  4. Once you’ve selected a user, click Submit Transfer. Both the current owner and the new owner should now receive an email with a link to complete the transfer. Click that link. Note that only one of you will need to do this in order to approve the transfer request.
  5. Once you’ve clicked the link you should be all set! The new owner will now have full edit access to the organization profile.

Note

Keep in mind that any user associated with your organization can submit a transfer request. This ensures that you can still transfer ownership of the organization even if the current owner cannot be contacted or is no longer able to access the LNLDB.

Caution

If you receive an unauthorized transfer request, please contact our Webmaster.

Last Modified: May 5, 2021

Upload Event Attachments
Clients

In addition to the information we may have collected from you when booking your event, it may sometimes be necessary to share additional attachments and/or media files with us to help us better provide our services to you. These files can be just about anything ranging from floorplans to MP3 files containing audio tracks to be played during a performance. This guide will provide step-by-step instructions explaining how to upload these files for your event.

Crew Chiefs

As a crew chief one of your responsibilities is to plan out how you will set up the systems that will run your event. These plans sometimes rely on various files such as pull lists and/or lighting plots. This guide will provide an overview of how you can upload these files for future reference so that you and others may benefit from these resources.


Upload Files for an Event

1. First, navigate to the event detail page in the LNLDB. In other words, visit lnl.wpi.edu/db then use the Events navigation menu to find the event.

  1. Once on the event detail page, click on the Files tab then click the yellow Edit button.
_images/edit.png
  1. Select the service(s) the file applies to (if any). If you’re unsure, feel free to leave this field blank.
_images/service.png

4. Next click the Choose File button. A popup will appear prompting you to select a file from the local file system on your computer.

_images/choose.png
  1. Once the file has been selected, use the Note field to provide a brief description of what the file is.
_images/note.png
  1. When you are done uploading all of your files, scroll down to the bottom of the page and click Save Changes.

And that’s it! Your files are now available on your event page.

Last Modified: April 23, 2021

How to Pay Your Bill

Once your event has ended, our Treasurer will be in touch to send you the bill. If you are acting on behalf of a WPI club, organization, or department, you will have the option to submit payments through Workday. This is the recommended approach, however you may also pay via cash or check. LNL does not accept credit cards.

Pay via Workday

You should have received an email from us with your most recent invoice. Look for the big yellow Pay Now button and click it to submit your Workday account information.

You’ll need to sign in if you haven’t already. Then, on the page that appears, review the event details and the cost breakdown. If anything on this page seems incorrect, stop what you are doing and contact our Treasurer.

If everything looks good, select your funding source and enter your worktag. Your worktag should end in AG, CC, GF, GR, or DE. If you have any additional comments for our Treasurer, be sure to provide them in the Comments field then hit Pay.

Once our Treasurer receives your request, they will create an Internal Service Delivery (ISD) in Workday. Be sure to approve the ISD when you receive it.

Pay by cash or check

To pay with cash or check, contact our Treasurer by emailing lnl-t@wpi.edu.

Last Modified: May 3, 2021


Member Resources

Accounts
Update your profile

Your profile on the LNL Database (LNLDB) contains a variety of information about you, most of which you can edit.

Accessing your profile

To access your profile, log into the LNLDB at lnl.wpi.edu/db. Once logged in, you will see Logged in as <Your Name> in the top right corner of the page. Clicking on <Your Name> will take you to your profile. Your profile has information like what events you have participated in, how many meetings you have attended, and how many hours you have spent on events, as well as your contact information and your training certificates.

Editing your profile

Click the blue Modify button to edit your profile. Here you can update user, contact and student info. Contact the Secretary at lnl-s@wpi.edu if you need to make changes to the non-editable fields. When you have completed your updates, click the blue Update Member and Return button at the bottom of the page to save your changes.

Note

Internal info can only be edited by those with Officer level access. Please reach out to our Secretary if this information is incorrect.

Last Modified: April 17, 2021

Update Your Communication Preferences

The LNLDB now allows you to have more control over what types of communications you receive from us. While you may not be able to opt out of all communications, in many cases you will have the ability to customize how and when you receive them.

Managing your preferences

If you haven’t already, log into the LNLDB and click your name in the top right corner of the page. This will take you to your user profile. Next, click on the large Preferences button to view your account preferences. Your communication preferences will be listed under the Communications section.

When you are done updating your preferences, don’t forget to hit Save!

Note

If you do not see the Preferences button on your profile page, then your current role does not support customizing your communication preferences. If this is the case and you are looking to opt out of LNL communications, please contact us.

Last modified: December 10, 2021

Set a password for non-SSO login

The recommended way to log into the LNL Database (LNLDB) is to use your WPI Microsoft account. However, you may also want to set a local password for those rare instances when Microsoft’s services are unavailable or if you find this method more convenient. There are two ways to enable this sign-in method: on your own or by contacting our Webmaster.

Set the password yourself

To set the password yourself, log into the LNLDB (using your WPI Microsoft account) then click on your name in the top right corner of the page. Next click the blue Modify button, then under the User Info section you should see a link to Set a password for non-SSO login. Click that link then enter your desired password. Passwords must be at least 8 characters long and contain at least one of each of the following:

  • a capital letter
  • a number
  • a non-alphanumeric character or symbol
Having trouble?

If you’ve been locked out of your account or otherwise can’t sign in, contact the Webmaster and they should be able to get you squared away.

Last Modified: April 17, 2021

Updating Membership Roles (Officers)

User roles (sometimes referred to as “groups”) determine what content specific users on the LNLDB can access. Examples of the various groups include officers, alumni, active members, associate members, and more.

Changing a User’s Role(s)

Caution

Permission Required: Change group membership of a user

In order to change user roles, you must have been assigned a role that gives you permission to change user group memberships. If the Groups field is not visible or is disabled, your current role(s) do not grant you adequate permission to change this setting.

To update a member’s roles, navigate to their profile in the LNLDB. The easiest way to do this is by navigating to Members > All Members and selecting the user you would like to edit. Click the blue Modify button and scroll down to the Internal Info section. In the Groups field, find and select each group you wish to make the user a member of. Check to make sure each of the desired groups is highlighted, then save your modifications by clicking the Update Member and Return button at the bottom of the page.

Note

Associating a new user will automatically trigger a welcome email

Last Modified: April 17, 2021

Connect your RT account to LNL Web Services

Important

This guide is intended only for users with an existing RT account

The RT integration makes it possible to manage the TFed database through other LNL web services such as the LNLDB and Slack. General users (without an account) can always submit tickets or comment on existing ones, however an account will be required for just about everything else. Once linked, privileged users in RT will be able to modify ticket information and perform other administrative tasks without the need to sign into RT directly.

Create an Auth Token

In order to link your RT account with your LNL account, you’ll first need to generate an Auth Token. Sign into RT then select Logged in as … > Settings > Auth Tokens from the menu bar.

Note

If you do not see this option, then unfortunately you do not have the necessary permissions to use the RT integration.

In the top right corner of the page, click Create. In the dialog that appears, enter your password and a name for your token. We recommend naming your token something like LNL Web Services so that it can be easily identified later.

_images/token-dialog.png

Once you click Create, your token will appear in a message at the top of the page. Copy the token (the text that appears between the quotation marks) and continue to the next step.

_images/token-confirmation.png

Caution

Remember: Treat your token like a password and do not share it with others! Your token will only be displayed once.

Activate the RT Integration Activate

Once you’ve generated an auth token, click the button above to start the setup process. You can also get there through your profile page by clicking the Preferences button, then scrolling down to the Request Tracker section and clicking Connect Account. When prompted, enter your token then click Submit.

And that’s it! Your accounts are now linked.

Note

Changing your password does not invalidate your auth token. If you wish to unlink your accounts, log into RT and revoke the token.

Last Updated: August 11, 2021

Adding pronouns to your profile

LNLDB users can add their personal pronouns to their profiles.

Editing your profile

Please see our other guide Updating your profile for instructions on how to access the editing form.

Adding pronouns

Looking at the top section (“User Info”), if you scroll down to the bottom, you will see a new field called “Pronouns”. Add your pronouns in this field, then scroll to the bottom and click the blue “Update Member and Return” button.

Last modified: December 10, 2021

Events
Checking into an Event

In order to obtain credit for both gaining and maintaining active membership, LNL has an electronic system for keeping track of the events members attend. Members are expected to check in when they arrive at the event and check out when they leave the event.

You may check into an event beginning at the event’s setup start time and may check out of an event as late as five hours after the event’s end time.



Checkin

From the Checkin menu, you must select the event you wish to check into using the radio buttons. Then, click Submit to check into the event.

_images/checkin.png

Checkout

After clicking on the Check out button, verify the hours you were at the event.

_images/checkout.png

Then enter the amount of time you spent assisting within each service category.

_images/hours.png

Note

The LNLDB will round to the nearest 15 minutes


Using the Bulk Checkin Feature _images/bulk-checkin.png

To open the bulk checkin tool, visit lnl.wpi.edu/crew then click Open Bulk Checkin. Once you’ve selected your event, ensure that the entry field is in focus and begin checking people in.

To check someone in or out, simply scan or swipe their student ID. If a match is found in our system, their checkin status will be toggled automatically. This means that once a crew member has checked in, all they need to do to check out is scan or swipe their card again (and vice versa).

Note

To launch this page you will need to be listed as a crew chief for an ongoing event

Hint

If you get an Invalid ID error, this means that the crew member’s student ID is not listed in their profile.

Last Modified: May 3, 2021

Create / Edit an Event

The event editor is a way for LNL members to create events in the LNLDB. It offers a more advanced and comprehensive approach when compared to the workorder wizard with additional options for specifying internal details.


Using the Event Editor

To access the event editor, start from the LNLDB, then select Events > Add Event from the navigation bar.

  1. Name and Location: All the basic information for the event goes here. This includes the event name, location, and description. Check the help text below each field for additional information and clarification on what each option does.
  2. Contact: This is where you’ll select the person who will serve as the event contact and the organization that will act as the client. Simply start by typing the name of the user or organization you wish to add into the respective field. As you type, the field will automatically search our database for a match. Once the user or organization appears in the search results, select it from the list. If the client you’re doing the event for is different than the client you’re billing, then note that the Client(s) and Client to bill fields may differ.
  3. Scheduling: This tab is where you will specify all the scheduling details for the event (i.e. start time, end time, etc.).
  4. Services: This is where you select which services LNL is providing for the event.

Tip

If you need to add more than 3 services to an event, start by filling out the first three form fields then click the Save Changes button at the bottom of the page. You’ll then be brought to the event page. Once you’re there, click Edit to go back and add the additional services.


Add Extras

Caution

Permission Required: Adjust event charges (Officers and Crew Chiefs)

In order to add extras or OneOff charges to an event, you must have been assigned a role that gives you permission to adjust event charges. By default, only Officers and the event Crew Chiefs will have this permission.

If you need to add extras to an event, such as a mirror ball, navigate to the event page, switch to the Services tab, and click the blue Modify Extras button on the right side.

Note

You can only add 1 at a time, so if you need to add multiple extra items, save your changes, then click Modify Extras again.


Add OneOff Charges

Caution

Permission Required: Adjust event charges (Officers and Crew Chiefs)

In order to add extras or OneOff charges to an event, you must have been assigned a role that gives you permission to adjust event charges. By default, only Officers and the event Crew Chiefs will have this permission.

These are usually very specific or custom charges that need to be added to a client’s bill. To add one of these charges, navigate to the Billing tab, then click the Add OneOff Charges button.

Last Modified: May 3, 2021

Creating Projection Events in Bulk

The LNLDB includes a neat little tool designed to help the Head Projectionist schedule several movies at once over a given time period. This feature is typically used to add the upcoming weekend movies for the coming term or semester all at once.

Caution

Permission Required: Create projection events in bulk

In order to use this tool, you must have been assigned a role that allows you to add new movies to our event schedule in bulk. If you do not see the option to Bulk Add Movies under Projection in the navigation bar, your current role(s) do not grant you adequate permission.

Schedule Movies in Bulk

Hint

This process is optimized for scheduling movies on recurring weekends (Fridays, Saturdays and Sundays). For individual projection events, or events taking place on weekdays, we recommend creating a new event as defined here.

To get started, navigate to Projection > Bulk Add Movies. Then follow the steps below.

Step 1

On the first page you will be asked to provide some basic information about the collection of movies you are about to add.

  • Contact: Type the name of the person who will serve as the event contact for these movies. As you type, the field will automatically search our database and display a list of users matching your query. Select the desired person from the search results to continue.
  • Billing: Enter the name of the organization that will be billed for these events (AKA the client). Like the Contact field, this field will search our database for a matching organization as you type. Select an option from the results to continue.
  • Date of first movie: Enter the planned date for the first movie in the series. You may either use the included calendar widget or enter the date manually in mm/dd/yyyy format.
  • Date of last movie: Enter the planned date for the final movie in the series. You may either use the included calendar widget or enter the date manually in mm/dd/yyyy format.

Hint

There must be at least one Saturday between your selected start date and end date (inclusive). The form will determine how many weekends to create events for based off of the number of Saturdays in your date range.

Once you have filled out the form, click Continue.

Step 2 _images/bulk-movies.png

You should now be presented with a form containing several rows - one for each weekend in the date range you specified in Step 1. In each row, enter the name of the movie that will be showing that weekend and select the desired showing times. The possible showing times correspond to the following time frames:

  • Friday: Friday from 8 - 11 PM
  • Matinee: Saturday from 2 - 5 PM
  • Saturday: Saturday from 8 - 11 PM
  • Sunday: Sunday from 8 - 11 PM

Note

There is no need to adjust the dates in the first column. Leave these fields as they are.

Once you have listed all of the movies you wish to add for the given time period, click Submit. You should then see a summary of all the movies that have been added to the database. Clicking on any of these links will take you directly to the corresponding event detail page.

Last Modified: May 6, 2021

Writing a Crew Chief Report

Crew chief reports (CC reports) are important records for future crew chiefs of similar events. These reports should be written not long after the event ends by each of the crew chiefs. This guide will explain where and how to write one.

Tip

Officers: Need to remind someone to complete their CC report? Use the Remind All button under the Reports tab on the event detail page.

Where to Write the Report

Reports are stored alongside events in the LNL Database (LNLDB), which can be accessed at lnl.wpi.edu/db. The easiest way to access the events you have been a crew chief for is by selecting Events > My Events from the navigation bar, which should take you to a list with a section titled Events as Crew Chief. From here you can select the blue CC Report button in the right column to write your report.

You can also get to it from the event detail page under the Reports tab. Click the New button to add a report.

Important

You will only have 14 days after the event to write your report so please be prompt and do not put it off!

What to Include in the Report

On the report page there are some questions to answer and two boxes. The left box is where you type your report, answering the listed questions. The right box will show a preview of the report, with formatting applied. When you have completed your report, click the Save Changes button and you are done!

Last Modified: May 3, 2021

Generate and Send a Bill (Treasurer)

The LNLDB allows you to easily create an invoice for an event based on the event information in our database and automatically generates an email to send to the client for gathering their Workday worktag details.

Generate an Invoice

You can generate an invoice or quote for an event at any time on the event detail page. Select the Billing tab, then under Bills click the blue Download Invoice or Download Quote button.


Billing a Client

Caution

Permission Required: Bill event

In order to create or update bills for an event, you must have been assigned a role that gives you permission to do so. If you do not see the Create Bill button, your current role(s) may not grant you adequate permission.

Create and Send a Bill

Note

The event must have already been reviewed before it can be billed. If the event status is Awaiting Review, please contact the officer responsible for reviewing the event before continuing.

  1. Click Create Bill on the event page. This button will only appear once the event has been reviewed.
  2. Enter the date billed and the total amount due. These fields will be pre-filled with the current date and the total amount from the Price Breakdown in the billing tab. Be sure to double check these values and update them if necessary.
  3. Next you will have the option to generate and send an email to the client to request their Workday worktag. If you do not wish to send an email at this time, click Save and Return. Otherwise click Save and Make Email.
  4. If you chose to send the email, the next page will automatically generate an email for you and give you the opportunity to edit the message and subject line. The User Recipients field allows you to define specific users to send the email to, while the Client Recipients field lists any applicable exec board email aliases. Once you’re satisfied with the setup, click Send Email. The bill will be added to the email automatically as an attachment.
Updating a Bill

To update the details of a bill, click the Update button next to the bill you wish to edit. Update the date billed and/or the amount then hit Save Changes. Clicking Reset Form will reset the Date billed and Amount fields.

Mark a Bill as Paid

There are a few different ways to mark a bill as paid. One of the easiest methods is to update the bill from the event detail page. Under the Billing tab, locate the bill then click the Mark Paid button. This button will also appear in a few additional places throughout the LNLDB, such as on the All Events page (Events > All Events).

Last Modified: May 3, 2021

Meetings
Create or Edit a Meeting

The LNLDB can store details about nearly any type of LNL meeting (General Body, Exec, Committee, etc.) whether they will occur in the future or have already happened. This is where LNL members can find meeting minutes, agendas, attendance records, and related files.

Caution

Permission Required: Modify Meeting Details

In order to create new meetings or send meeting notices, you must have been assigned a role that allows you to modify meeting records. If you do not see the option to create a new meeting under Meetings in the navigation bar, your current roles do not grant you adequate permission.

To create a new meeting or edit an existing one:

  1. In the navigation bar, select Meetings > New Meeting.
  2. Select the meeting type from the dropdown.
  3. Next, you’ll have the option to select the location where your meeting will take place. If the meeting will be virtual, select Zoom – Virtual Meeting.
  4. In the Datetime field, be sure to select the date and time for when your meeting will begin. Dates must be in yyyy-mm-dd format and times should be in hh:mm a format.
  5. For Duration, specify how long the meeting will last. This field accepts a quantifier followed by a unit of time, such as:
    1. 30 seconds
    2. an hour
    3. 3 days
  6. If you would like to add an agenda, update meeting minutes, or record attendance, begin by selecting the respective tab from the tab bar. For more details on how to update the attendance, see Update Attendance.
  7. Finally, click Save Changes

To delete a meeting:

  1. Follow the process above as if you were to edit the meeting.
  2. Scroll down to the bottom of the page and click Delete.
  3. Finally, click Yes! to confirm the action.
Update Attendance

To add someone to the meeting attendance list, simply type their name into the text box. As you type, the field will automatically search our database for that user. If a user matching your query does not yet exist in our database, it will search WPI’s LDAP system. Once you see the listing for the user you would like to add in the search results, select the listing to add their name to the list.

To remove someone from the attendance list, click the trash can icon next to their name.

Last Modified: September 9, 2021

Send a Meeting Notice Email

Once a meeting has been created (see Create or Edit a Meeting), you can send out meeting notifications. This is often used by the Secretary to send meeting notices to the club.

Caution

Permission Required: Modify Meeting Details

In order to create new meetings or send meeting notices, you must have been assigned a role that allows you to modify meeting records. If you do not see the option to create a new meeting under Meetings in the navigation bar, your current roles do not grant you adequate permission.

To send a meeting notice for a specific event:

  1. Start by logging into the LNLDB, then click Meetings > View Meetings.
  2. Select the meeting you wish to send a meeting notice email for.
  3. On the page that appears, select Emails from the sidebar. This will list all of the emails that have been sent for this meeting.
_images/email-list.png
  1. Click Send Meeting E-Mail and begin filling out the form.
    • Subject: This will be the subject line of your email (i.e. “LNL General Body Meeting”)
    • Message: This will be the body of your email. Ensure that your message contains all of the necessary meeting details such as when the meeting will take place and how to get there (if applicable).
    • Email to: Select the email alias you wish to send the meeting notice to.
    • Events: You may skip this field
_images/email-form.png
  1. Once you are satisfied with the details, click Save Changes. The LNLDB will then send your email and take you back to the previous page.

Tip

To the right of the Message field, the LNLDB will show you a preview of the body of your email. The LNLDB uses Markdown for formatting and will display the result in realtime. To learn more about the Markdown formatting options available to you, click the blue Help? button located above the preview box.

Last Modified: May 17, 2021

Equipment
Getting Started with Snipe
Introduction

Snipe IT is the system that LNL uses to track all the things we own. There are two main categories that items can fall into within Snipe - Assets and Accessories. Assets are items that you want to track individually. All assets must have a unique asset tag - that is how they are identified. Accessories are things that you want to track only as a group. Accessories are very limited and should only be used for very small things or things that lack a good place to put an asset tag.

_images/home.png

To view LNL’s inventory in Snipe, visit the LNLDB home page and select Snipe from the Quick Links menu.

See also

Log into Snipe

Note

Only active members of LNL will have access to Snipe. If you do not already have an account in Snipe, click here to obtain login credentials. Access will be read-only.

Once you are logged in, you can view assets, by selecting Assets > List All from the sidebar. You can now search for specific items using the search field on this page. Use this search field when searching for items, as the one at the top of the page only conducts searches using asset tags.

If for example you want to find out how many Source 4s we own, select Assets > List All, then search for “source 4”.


Rentals

The LNLDB has a helpful tool to make checking equipment in and out much easier. Simply scan the asset tags for each of the items you wish to check in or out and let Snipe take care of the rest!

Checkout

Select Equipment > Inventory Checkout and follow the instructions on the page. To scan an asset tag, point the barcode scanner at the tag and pull the trigger. The scanner should add a carriage return automatically. For accessories, there are special barcodes located in the lids of bins or the drawers of workboxes. Scan accessory barcodes multiple times for the number of items you are checking out.

Checkin

The checkin process is essentially the same as the checkout process. Select Equipment > Inventory Checkin and follow the instructions on the page.

Note

If you are doing one-off checkins or checkouts you can do it in Snipe. Just locate the asset and click checkin/checkout then select the user.

Need to add a Rental Client?

If the rental client isn’t listed in the dropdown, contact our Technical Director for assistance.

Last Modified: May 17, 2021

Access Laptop Passwords

LNL devices are password-protected for security. As an active LNL member, you have access to these passwords through the LNLDB and can use them to access the laptops as necessary at LNL functions.

Which password do I need?

In most circumstances all you need is the regular password to the laptop. The regular password will let you log into the laptop, change most settings, and use most applications. LNL’s MacBooks are also setup with a managed app store where you can install applications typically used by LNL all without the administrator password. For more details please review Installing Software on the MacBooks.

If you ever need an administrator password you may access it as described below, however please ensure that you have exhausted all other options first. A log is kept of who accesses the administrator password and when and can be viewed at any time by members of the executive board. The MacBooks may also be reimaged at any time, with or without notice, whenever the administrator password has been used.

Caution

Only active members will have access to the administrator password. This password should rarely ever be used. The MacBooks are set up in such a way that you shouldn’t ever really need it. Your use of the password will be logged.

Tip

The administrator password will change from time to time, while the regular password remains the same. As such, you do not need to login to check the regular password each time you would like to use a laptop!

Accessing Passwords

If you are an active or alumni LNL member, accessing the laptop passwords is pretty straightforward:

  1. Log into the LNLDB
  2. In the menu at the top of the page, select Equipment > Laptops
  3. Select View Password for the device you wish to view the password for

Tip

All the laptops LNL owns are labeled both on the laptop itself and on the associated road case. Make sure you select the password that corresponds to the device you are using.

Last Modified: May 1, 2021

Installing Software on the MacBooks

The LNL MacBooks are managed through LNL’s own custom Mobile Device Management (MDM) platform. The MDM handles several key functions related to the management of these computers including the upkeep of their software. If you are looking to upgrade or install software on any of these devices, we highly recommend starting with the first approach outlined below.

Managed Software Center

On each of LNL’s managed MacBooks you should find an application called the Managed Software Center. For your convenience this application should already be pinned to the Dock. The Managed Software Center (MSC) is essentially LNL’s own custom App Store where you can go to install software packages that have been approved and pre-configured by the Webmaster. It’s based off an open source project called Munki which handles the entire installation process for you. In fact, it allows you to install or update software without ever needing to enter an admin password!

Whenever you are looking to install new software or update an existing application, we recommend checking MSC first. If your desired software is not available in MSC, contact our Webmaster to request that it be added to our catalog.

_images/munki.png

Tip

If you don’t see an application listed on the Featured tab in MSC, that doesn’t necessarily mean the software isn’t available. Be sure to check the respective category listings (i.e. Sound, Lighting, etc.) as well.

Requesting Software

If you can’t find your application in the Managed Software Center, you can send our Webmaster a request to install the software for you. If you don’t need the software installed immediately, this is the recommended approach as it ensures your software will be set up properly and will remain on the device even after the device gets reimaged.

To request software, log into the LNLDB then select Equipment > Laptops from the navigation bar. Next click Request Software, then New App and fill out the form that appears. Be sure to enter the full name of the application and provide the name of the developer if you know it. Once your request has been approved by the Webmaster, the software will be installed for you.

See also

Request Software

Training
Request a PIT

In order to safely and correctly operate LNL’s projection equipment, we offer our members various levels of training, called PITs (Projectionists in Training). PITs are leveled one through six and must be completed in order. Upon completion of all six PITs, a member may take a written test and a practical to complete their training. Each PIT gives you access to operate more of the equipment in the booth while running a projection event.

Requesting a PIT
  1. In the navigation bar select Projection > Request Training.
  2. Select the type of training you would like to schedule from the PIT dropdown.
  3. Optionally, you may request a specific date and time in the Request Date / Time field.
    • Dates can be selected by entering the date in yyyy-mm-dd format in the first field or by selecting a date from the calendar widget.
    • Times can be selected by entering a date in hh:mm a format in the second field or by selecting a time from the time widget.
  4. After selecting the type of training and optionally a date and time, click Submit Request.

The Head Projectionist will be notified of your request and will reach out to confirm a date and time.

Hint

If you have not completed any PITs and you are unsure of which level of training you should request, select PIT 1.

Last Modified: May 17, 2021

Manage Member Training Records

Here at LNL, safety is our top priority. Due to the nature of our work and the equipment we use, we require that our members undergo training before carrying out certain activities. This includes, but is not limited to: rigging truss, operating aerial work platforms / lifts, and working with three-phase electrical power. To help us ensure that our members are properly trained, the LNLDB maintains records of all member training and certifications.

See also

For more information about our training policies and procedures or to learn more about upcoming training sessions, contact our Technical Director.


View Training Records

Caution

If you do not see Members > Training in the navigation bar, then you do not have permission to access member training records. Typically, you will need to be an active or alumni member.

There are actually a few different places in the LNLDB where you will find training records. The first is the training dashboard. To get to the training dashboard select Members > Training from the navigation bar.

You can also view training records for specific individuals on the member’s profile page. Training records typically include the type of training, the date the training was performed, who issued the training, and when it expires.


Update Training Records

Caution

Permission Required: Add training

In order to update training records, you must have been assigned a role that allows you to add training records to the database. If you do not see the big blue Enter Training button on the training dashboard, your current role(s) do not grant you adequate permissions to do any of the following.

Enter New Training
  1. Start by selecting Members > Training from the navigation bar.
  2. Click the big blue Enter Training button.
  3. Under Training type, select the type of training that was performed.
  4. Enter the date on which the training session was held. You may use the built-in calendar widget or enter the date manually in mm/dd/yyyy format.
  5. If the training session was conducted by an LNL member, enter their name into the Trainer field. As you type, the field will automatically search the database for users that match your query. Select the correct user from the results to continue. For trainings conducted by an external organization you may leave this field blank.
  6. Under Trainees, enter the names of each individual person who attended the training session. As you type, the field will automatically search the database for users that match your query. Select the correct user from the results then repeat until all the trainees are listed.
  7. If the training has an expiration date, be sure to enter that date into the Expiration date field. You may use the built-in calendar widget or enter the date manually in mm/dd/yyyy format.
  8. Finally, if you wish to include any notes about the training, enter them in the Notes field. When everything looks good, click Save.

Note

If the type of training you wish to record is not listed in the dropdown, contact our Webmaster.

Note

Typically, the person running the training session must already have a valid training record before they can issue training to others.

Add Notes

You may update training notes at any time using the cards displayed on the user’s profile page.

  1. Navigate to the user’s profile page.
  2. Under Trainings, locate the card for the respective training.
  3. Click Edit notes, then update the notes as needed.
  4. Click Save
Revoke Training

Sometimes it may be necessary to revoke someone’s training if they fail to adhere to established safety procedures. To revoke a training:

  1. Navigate to the user’s profile page.
  2. Under Trainings, locate the card for the respective training.
  3. Click Revoke

Danger

Once training has been revoked, the action cannot be undone. The training will need to be reentered once the user has been retrained.

Last Modified: May 17, 2021

Integrations
Accept Song Requests (Spotify)

The LNLDB leverages the Spotify Web API to make it super easy to collect and queue song requests for events like Wall of Sound. This guide will explain how you can set up a new song request session for your event and how you can configure it to fit your needs.


Create a New Session

Song requests can be enabled for any event that has been approved and has not yet been reviewed. To get started, you’ll need to create a new Spotify session on the event detail page.

_images/new.png
  1. Navigate to the event detail page for the specific event you would like to collect requests for.
  2. Select the Apps tab and look for the Spotify applet.
  3. Click the New Session button.
  4. Fill out the form, then click Save Session. To learn more about the options presented in this form, check out Update Session Settings below.

Your session is now ready to go. Once you have returned to the event page, you’ll be presented with a link to the page where your event guests will be able to make their requests.

Caution

Permission Required: Create a Spotify session

In order to create a new session, you must have been assigned a role that gives you permission to do so for a given event. By default, only Officers and the event’s Crew Chiefs will have this permission. If you do not see the Spotify applet under the Apps tab on the event detail page, then your current role(s) do not grant you adequate permissions to perform this action.

Tip

To make sharing your link easier, the LNLDB can also generate a QR code for you. Just click QR Code to display or download the code.


Update Session Settings

You can view or manage the configuration of your song request session at any time from the Spotify applet on the event detail page.

Caution

Permission Required: Update a Spotify session

In order to edit a session, you must have been assigned a role that gives you permission to do so for a given event. By default, only Officers and the event’s Crew Chiefs will have this permission. If you do not see the Configure Session button in your Spotify applet, then your current role(s) do not grant you adequate permissions to perform this action.

  1. Navigate to your event’s detail page and select the Apps tab.
  2. In the Spotify applet, click the Configure Session button. This will take you to the same form you filled out when you created the session.
  3. Make the desired changes, then click Save Session.

An overview of each of the settings is outlined below:

  • Spotify Account: The Spotify account that will be used for this event. Tracks submitted to this session’s queue will play on whatever device this user is currently logged into.
  • Accepting requests: If this is enabled, you’re ready to accept song requests. To stop accepting song requests, simply uncheck this box. You can come back and toggle this setting on or off at any time.
  • Allow explicit: By default, we allow guests to request explicit music. If you would prefer not to allow this, uncheck this box.
  • Automatically approve requests: If you don’t particularly care what ends up on your queue, you can select this option to allow the LNLDB to automatically attempt to queue requests as they come in.
  • Restrict to LNL members: Check this box for a private session. Users will need to be logged in to request songs.
  • Require payment: If donations are required to make a request (i.e. Wall of Sound), check this box.
  • PayPal.Me Link: If you are collecting donations using PayPal, paste your PayPal.Me link here. If you do not have one, you can always create one for free.
  • Venmo: If you are collecting donations using Venmo, enter your Venmo username.
  • Venmo verification: Venmo occasionally asks users to verify that they are sending money to the correct person. To ensure that users can complete this step, you should enter the last 4 digits of your phone number here if you are collecting donations through Venmo.

Manage Song Requests

As requests come in, you may need to approve and/or queue each individual request. For events where donations are collected, the LNLDB also allows you to keep track of which users have paid the fee. If you have the necessary permissions, you’ll see the relevant buttons appear in the table as needed.

Caution

Permission Required: Approve Song Requests

To manage song requests, you will need to have been assigned a role that gives you permission to approve song requests for a given session. By default, only Officers and the event’s Crew Chiefs will have these permissions. If you do not see any buttons on the requests page, then your current role(s) do not grant you adequate permissions to manage song requests.

_images/approve.png

New requests will appear at the top of the page. If the requests aren’t automatically approved and queued, then you will be presented with options to Approve or Deny the request. To learn more about the requested track, you can always click on its name to open it in Spotify.

Once a track has been approved, if payment is required, you’ll be asked to confirm that the request has been paid for. If payment is not required, you’ll instead see the Queue button. Click this to attempt to add the track to the queue in Spotify.

Note

If Spotify is not currently active on any of our devices, you’ll likely get an error when attempting to queue tracks. All you will need to do is launch Spotify and start playing something on the device you intend to use. Just make sure you are using the same Spotify account you selected when configuring the session!

_images/playing.png

If all goes well, you should be able to see all of your queued tracks in Spotify. In addition to the list of pending requests, the LNLDB will also show you a list of all the tracks you have added to the queue during your session as well as the track currently being played (if applicable). The LNLDB will do its best to estimate the approximate runtime of your queue, although if you add tracks to the queue from within Spotify itself, the LNLDB may not be able to accurately account for the additional time.

Tip

Make sure to refresh the page from time to time as new requests may have come in!

Last Modified: February 27, 2022

Report Bugs

Oh no! If you’re here then that likely means…

Well, as hard as we try to keep things running smoothly, the fact of the matter is, you cannot win them all. If you’ve encountered a bug while using the LNL Database, please let us know. Our Webmaster does get notified each time there is a server error, but it often helps to have a bit more context, so please don’t hesitate to reach out.

You can submit a bug report by doing any of the following:

  1. Submit a ticket online or through Slack
  2. Email tfed-db@wpi.edu
  3. Submit a new issue on GitHub

In your message, be sure to tell us where you were on the site, what you were doing, and what went wrong. The more details you can provide, the better.

Getting Started

Welcome! If you’re interested in learning more about how to develop software solutions for LNL, then you’ve come to the right place.

The LNL Database is at the center of it all and is an incredibly valuable resource for our club. The database itself is complemented by a number of services and integrations designed to make everyone’s lives just a little bit easier. Use this guide to learn more about the database and how you can get started working with it today!

Source Code

The source code for the LNL Database is open source and free to use. It runs on Python 3 and Django 2.2 or later. Visit the GitHub repository for more information.

Join the Discussion

We are now using GitHub Discussions as a way for members of the community to share their thoughts and ask questions. To learn more or to join in on the discussion, click here.

Become a Contributor

Are you familiar with Python, HTML, CSS, and/or Javascript? If so, you may be interested in becoming a contributor on the LNLDB project. To learn more about how to contribute click here.

API

The LNL Database has a built-in REST API for communicating with external applications. While the API currently only has access to a limited portion of the database, it makes LNL’s data much more accessible. Our API enables developers like you to create all new interfaces and extensions for LNL’s web services. We hope it will spark greater creativity and innovation as we strive to offer the best experience possible for our members and our clients.

See also

The API Reference can be found here (login required)

LNLDB API

The LNL API is a simple REST API which can be used to connect apps and services with the LNL Database (LNLDB). This guide provides an overview of the API and its authentication methods.


Getting Started

The LNL API can be accessed through standard HTTP requests and will return JSON metadata. To access protected information, your application will be required to authenticate with the LNLDB first. The API is currently configured to respond to the following HTTP Methods:

Method Action
GET Retrieves a specified resource
POST Sends information to the database
OPTIONS Provides communication options for the endpoint

Note

If attempting to communicate with the API through methods such as ajax, note that by default, CORS prohibits cross-origin requests. You may need to register your application with the API before using such methods. Contact lnl-w@wpi.edu for assistance.


API Reference

View Reference


Authentication

While most of our endpoints are public, some do require authentication. Check out our Authentication guide for more information.

Contributing to the Project

The source code for the LNL Database project is open source and can be found on GitHub. Any current or former LNL member is more than welcome to contribute to this project. When doing so, we ask that you familiarize yourself with some of the best practices outlined below and let us know if you have any questions. Feel free to email lnl-w@wpi.edu if you ever need more assistance and happy coding!

Getting Started

If you haven’t already, you’ll want to fork the LNLDB project and clone or download your fork onto your device. Be sure to follow the directions provided in the README file to get set up. You’ll also need to switch to a new branch before making any changes.

Testing

Before submitting new features for review, we strongly encourage writing tests for your code. All tests should pass and cover a majority of the lines written. Pull requests that do not contain adequate test coverage are less likely to be accepted.

We recommend writing tests for larger models and all of your views. In most cases, this is enough to provide adequate coverage. Examples for how to write some of these test cases are provided below.

Tip

When writing test cases, be sure to test multiple inputs; especially edge cases. Test both valid inputs and invalid inputs.

Models
from django.test import TestCase
from django.utils import timezone
from events.tests.generators import UserFactory
from . import models

class ProjectionistModelTests(TestCase):
    def setUp(self):
        self.user = UserFactory.create(password="123")
        self.projectionist = models.Projectionist(user=self.user)
        self.projectionist.save()

    def test_expired(self):
        today = timezone.datetime.today().date()
        yesterday = today + timezone.timedelta(days=-1)
        tomorrow = today + timezone.timedelta(days=1)

        self.projectionist.license_expiry = today
        self.projectionist.save()
        self.assertTrue(self.projectionist.expired)

        self.projectionist.license_expiry = yesterday
        self.projectionist.save()
        self.assertTrue(self.projectionist.expired)

        self.projectionist.license_expiry = tomorrow
        self.projectionist.save()
        self.assertFalse(self.projectionist.expired)

When writing unit tests for models, you typically only need to test the properties that you have defined for the model (if any). In this case we are testing the expired property on a Projectionist object. We start by subclassing TestCase and override the default setUp() function to create objects that we will use frequently in our tests. In this case, many of these tests will use an instance of Projectionist, so we create a new Projectionist object.

Model Factories

Now you might notice that we also created a dummy user here using UserFactory. UserFactory is one of several model factory classes which allow you to create objects from certain models quickly and easily. These model factories will fill in dummy data for each required field unless otherwise specified when you create the object. A list of available model factories is included below:

  • UserFactory
  • BuildingFactory
  • LocationFactory
  • CategoryFactory
  • ServiceFactory
  • EventFactory
  • Event2019Factory
  • CCInstanceFactory
  • CCReportFactory
  • OrgFactory
  • FundFactory
Views

Test cases for views are a bit different when compared to model test cases. They can become fairly complicated, but fortunately there are a few shortcuts that can help make things a bit easier. Here’s an example of two different test cases used to check a couple of our more typical views:

from data.tests.util import ViewTestCase
from django.core.files.uploadedfile import SimpleUploadedFile
from django.contrib.auth.models import Permission
from django.urls.base import reverse
from django.utils import timezone
from . import models
from meetings.models import mtg_attachment_file_name

class MeetingsViewTest(ViewTestCase):
    def setUp(self):
        super(MeetingsViewTest, self).setUp()  # Always include a call to super to take full advantage of the ViewTestCase class
        self.meeting_type1 = models.MeetingType.objects.create(name='Exec')
        self.meeting = models.Meeting.objects.create(datetime=timezone.now(), meeting_type=self.meeting_type1)
        self.meeting2 = models.Meeting.objects.create(datetime=timezone.now(), meeting_type=self.meeting_type1)
        path = models.mtg_attachment_file_name(self, "TotallyAFile.png")
        f = SimpleUploadedFile(path, b"some content")
        self.attachment = models.MtgAttachment.objects.create(name="Attachment1", file=f, author=self.user, meeting=self.meeting)

    def test_viewattendace(self):
        # By default, should not have permission to view attendance
        self.assertOk(self.client.get(reverse("meetings:detail", args=[self.meeting.pk])), 403)

        permission = Permission.objects.get(codename="view_mtg_attendance")
        self.user.user_permissions.add(permission)

        self.assertOk(self.client.get(reverse("meetings:detail", args=[self.meeting.pk])))

    def test_modify_att(self):
        # By default, should not have permission to modify attachments
        self.assertOk(self.client.get(reverse("meetings:att-edit", args=[self.meeting.pk, self.attachment.pk])), 403)

        permission = Permission.objects.get(codename="edit_mtg")
        self.user.user_permissions.add(permission)

        # Will also need view_mtg permissions for redirect
        permission = Permission.objects.get(codename="view_mtg_attendance")
        self.user.user_permissions.add(permission)

        self.assertOk(self.client.get(reverse("meetings:att-edit", args=[self.meeting.pk, self.attachment.pk])))

        # If attachment event id does not match event id throw permission denied
        self.assertOk(self.client.get(reverse("meetings:att-edit", args=[self.meeting2.pk, self.attachment.pk])), 403)

        path = models.mtg_attachment_file_name(self, "TotallyAFile.png")
        f = SimpleUploadedFile(path, b"some content")
        valid_data = {
            "name": "Test File",
            "file": f,
            "private": True,
            "submit": "Submit"
        }

        self.assertRedirects(
            self.client.post(reverse("meetings:att-edit", args=[self.meeting.pk, self.attachment.pk]), valid_data),
            reverse("meetings:detail", args=[self.meeting.pk]) + "#minutes"
        )

There’s a lot to unpack here, so let’s work our way through it from top to bottom. If you look at the import statements you’ll notice that we import ViewTestCase. This is a custom test case class which we have developed to provide shortcuts for testing views. Next, there’s something called SimpleUploadedFile. This is used whenever you need to test a form with a file upload field. You’ll also notice we’ve imported the Permission model so that we can check that only users with the proper permissions can access a given view. Finally, when it comes to dealing with dates and times, we import timezone rather than datetime. This helps us avoid running into naive datetimes.

Next take a look at the setUp() function. We are once again overriding this function to set up some commonly used objects for our tests, however note that the first line makes a call to super. This doesn’t necessarily need to be the first line, however it does need to be included in the setup if you intend to test permissions (which you should). The setUp() function defined by ViewTestCase creates a new user (self.user) and logs them in for you.

The first test case is for a very basic view. For this view, we are only interested in ensuring that the view can load successfully. That being said, this view requires certain permissions to access, so first we will want to check that a user with no permissions will be denied access. After that, we add the permission(s) a user would need to self.user and try again. To check if the page loads as expected, we use the assertOk function provided by the ViewTestCase class to check for a HTTP status code of 200 (or some other code if specified).

The second test case is a bit more complex. We start out the same way we did with the first view, except in this case, you’ll notice that we have actually added two permissions for the user. This is because when the user successfully submits the form that is presented on this page, they will be redirected to a new page (which should have its own test) and that page requires a different permission. The next chunk handles checking that the page actually redirects when valid data is posted.

Forms and Formsets

Most views will follow a similar format to the views tested above, so you’ll just need to set up and test various GET and POST requests. When submitting form data, another thing to take note of is whether the form fields will have a prefix or if the form will include formsets. If so, valid form data may look something more like this:

valid_data = {
    "main-TOTAL_FORMS": 1,
    "main-INITIAL_FORMS": 0,
    "main-MIN_NUM_FORMS": 0,
    "main-MAX_NUM_FORMS": 1000,
    "main-0-crew_chief": str(self.user.pk),
    "main-0-service": str(service.pk),
    "main-0-category": "",
    "main-0-setup_location": str(location.pk),
    "main-0-setup_start_0": timezone.now().date(),
    "main-0-setup_start_1": timezone.now().time(),
    "event_name": "Some Event",
    "description": "We want to have an event to do event things",
    "save": "Submit"
}

See also

For more details on formsets, check out the Django Documentation

It may take a bit of practice to get used to at first, but writing tests for your code will save you time in the long run and significantly limit the number of bugs you introduce. If you’re new to test driven development, now is a great time to learn more about it! And if you are struggling with writing any of your tests, take a peek at the several tests that have already been written for the existing code.

Documentation

Any time you make changes to the code or add a new feature, you should take some time to update the documentation accordingly. If you’re adding new models or views, you can do this simply by including block comments like this:

class NewClass(models.Model):
    """A new class I just created as an example"""
    some_field = models.CharField(max_length=100)
    ...

These comments will be added to the documentation automatically the next time it’s compiled. You should also make sure that any related help guides are also updated. Everything you need to edit the documentation can be found in the docs module.

To compile the docs, navigate to the docs directory via the command line and run:

make html

And that’s all there is to it! This project’s documentation is an incredibly valuable resource for both our users and contributors like you. So help us out by doing your part to keep our documentation fresh and up-to-date.

Submitting your Code

Once you’ve managed to write some code, verified that all the tests pass, and updated the documentation (if applicable), it’s time to open a pull request. Once you’ve opened up your pull request, our Webmaster will begin reviewing your changes. If everything is in order, it will be merged and deployed with the next release.

Every contribution matters and we want to thank you all for your support. If at any time you get stuck or have questions about anything that isn’t covered by the documentation, we invite you to join the #webdev channel on Slack or email the Webmaster at lnl-w@wpi.edu.

Accounts

This module is used to maintain user accounts and profile information.

Models

class accounts.models.Officer(*args, **kwargs)[source]

Represents an Officer position

Parameters:
  • id (AutoField) – Id (required)
  • user (OneToOneField to User) – User
  • title (CharField) – Officer position (required)
  • img (OneToOneField to ProfilePhoto) – Img
exception DoesNotExist
exception MultipleObjectsReturned
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

img

OneToOneField(blank=True, null=True, related_name=”officer_img”, on_delete=SET_NULL(), to= ProfilePhoto)

img_id

Raw (integer) FK for img

objects = <django.db.models.manager.Manager object>
title

CharField(verbose_name=”Officer Position”, max_length=60)

user

OneToOneField(blank=True, null=True, related_name=”exec_position”, on_delete=SET_NULL(), to= User)

user_id

Raw (integer) FK for user

class accounts.models.PhoneVerificationCode(*args, **kwargs)[source]

Used for temporarily saving the last code sent to a user to verify their phone number

Parameters:
  • id (AutoField) – Id (required)
  • user (OneToOneField to User) – User (required)
  • code (BigIntegerField) – Code (required)
  • timestamp (DateTimeField) – Timestamp (required)
exception DoesNotExist
exception MultipleObjectsReturned
code

BigIntegerField()

get_next_by_timestamp(*, field=<django.db.models.fields.DateTimeField: timestamp>, is_next=True, **kwargs)
get_previous_by_timestamp(*, field=<django.db.models.fields.DateTimeField: timestamp>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
timestamp

DateTimeField(auto_now_add=True)

user

OneToOneField(related_name=”verification_codes”, on_delete=CASCADE(), to= User)

user_id

Raw (integer) FK for user

class accounts.models.ProfilePhoto(*args, **kwargs)[source]

Officer profile photo

Parameters:
  • id (AutoField) – Id (required)
  • officer (OneToOneField to User) – Officer (required)
  • img (ImageField) – Image (required)
exception DoesNotExist
exception MultipleObjectsReturned
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

img

Just like the FileDescriptor, but for ImageFields. The only difference is assigning the width/height to the width_field/height_field, if appropriate.

objects = <django.db.models.manager.Manager object>
officer

OneToOneField(related_name=”img”, on_delete=CASCADE(), to= User)

officer_id

Raw (integer) FK for officer

officer_img

Accessor to the related object on the reverse side of a one-to-one relation.

In the example:

class Restaurant(Model):
    place = OneToOneField(Place, related_name='restaurant')

Place.restaurant is a ReverseOneToOneDescriptor instance.

class accounts.models.User(*args, **kwargs)[source]

Extended User Class

Parameters:
  • id (AutoField) – Id (required)
  • password (CharField) – Password (required)
  • last_login (DateTimeField) – Last login
  • is_superuser (BooleanField) – Designates that this user has all permissions without explicitly assigning them. (default=False)
  • username (CharField) – Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only. (required)
  • first_name (CharField) – First name (required)
  • last_name (CharField) – Last name (required)
  • email (EmailField) – Email address (required)
  • is_staff (BooleanField) – Designates whether the user can log into this admin site. (default=False)
  • is_active (BooleanField) – Designates whether this user should be treated as active. Unselect this instead of deleting accounts. (default=True)
  • date_joined (DateTimeField) – Date joined (default=<function now at 0x7f60a49248c0>)
  • wpibox (IntegerField) – Wpi box number
  • phone (CharField) – Phone number
  • carrier (CharField) – By selecting your cellular carrier you consent to receiving text messages from LNL (default=)
  • addr (TextField) – Address / office location
  • mdc (CharField) – Mdc
  • nickname (CharField) – Nickname
  • student_id (PositiveIntegerField) – Student id
  • class_year (PositiveIntegerField) – Class year
  • locked (BooleanField) – Locked (default=False)
  • away_exp (DateField) – Away status expiration
  • onboarded (BooleanField) – Onboarding complete (default=False)
  • pronouns (CharField) – Pronouns
  • groups (ManyToManyField to Group) – The groups this user belongs to. A user will get all permissions granted to each of their groups. (required)
  • user_permissions (ManyToManyField to Permission) – Specific permissions for this user. (required)
exception DoesNotExist
exception MultipleObjectsReturned
addr

TextField(verbose_name=”Address / Office Location”, blank=True, null=True)

all_orgs

All organizations the user is associated with

auth_token

Accessor to the related object on the reverse side of a one-to-one relation.

In the example:

class Restaurant(Model):
    place = OneToOneField(Place, related_name='restaurant')

Place.restaurant is a ReverseOneToOneDescriptor instance.

away_exp

DateField(verbose_name=”Away Status Expiration”, blank=True, null=True)

billingemail_set

Reverse Manager for events.BillingEmail’s email_to_users

carrier

CharField(verbose_name=”Cellular Carrier”, max_length=25, blank=True, null=True, default=””, choices=[(‘’, ‘Opt-out’), (‘txt.att.net’, ‘AT&T’), (‘myboostmobile.com’, ‘Boost Mobile’), (‘mms.cricketwireless.net’, ‘Cricket’), (‘msg.fi.google.com’, ‘Google Fi’), (‘mymetropcs.com’, ‘Metro PCS’), (‘mmst5.tracfone.com’, ‘Simple Mobile’), (‘messaging.sprintpcs.com’, ‘Sprint’), (‘tmomail.net’, ‘T-Mobile’), (‘vtext.com’, ‘Verizon’), (‘vmobl.com’, ‘Virgin Mobile’), (‘vmobile.ca’, ‘Virgin Mobile Canada’), (‘vtext.com’, ‘Xfinity Mobile’)], help_text=”By selecting your cellular carrier you consent to receiving text messages from LNL”)

Cellular carrier: By selecting your cellular carrier you consent to receiving text messages from LNL

ccinstances

Reverse Manager for events.EventCCInstance’s crew_chief

ccreport_set

Reverse Manager for events.CCReport’s crew_chief

ccreportreminders

Reverse Manager for events.ReportReminder’s crew_chief

class_year

PositiveIntegerField(blank=True, null=True, validators=[<django.core.validators.MinValueValidator object at 0x7f60a2aabb90>, <django.core.validators.MaxValueValidator object at 0x7f60a2aabb50>])

connected_services

Reverse Manager for data.Extension’s users

contact

Reverse Manager for events.BaseEvent’s contact

crewchiefx

Reverse Manager for events.Event’s crew_chief

crewx

Reverse Manager for events.Event’s crew

equipmentmaintentry_set

Reverse Manager for inventory.EquipmentMaintEntry’s user

event_records

Reverse Manager for events.CrewAttendanceRecord’s user

eventapprovals

Reverse Manager for events.BaseEvent’s approved_by

eventbillingreview

Reverse Manager for events.BaseEvent’s reviewed_by

eventcancellations

Reverse Manager for events.BaseEvent’s cancelled_by

eventclosings

Reverse Manager for events.BaseEvent’s closed_by

exec_position

Accessor to the related object on the reverse side of a one-to-one relation.

In the example:

class Restaurant(Model):
    place = OneToOneField(Place, related_name='restaurant')

Place.restaurant is a ReverseOneToOneDescriptor instance.

get_carrier_display(*, field=<django.db.models.fields.CharField: carrier>)
get_next_by_date_joined(*, field=<django.db.models.fields.DateTimeField: date_joined>, is_next=True, **kwargs)
get_previous_by_date_joined(*, field=<django.db.models.fields.DateTimeField: date_joined>, is_next=False, **kwargs)
group_str

Groups the user belongs to

groups

Reverse Manager for accounts.User’s groups

has_perm(perm, obj=None)[source]

Returns True if the user has the specified permission. This method queries all available auth backends, but returns immediately if any backend returns True. Thus, a user who has permission from a single auth backend is assumed to have permission in general. If an object is provided, permissions for this specific object are checked.

This differs from the default in that superusers, while still having every permission, will be allowed after the logic has executed. This helps with typos in permission strings.

hours

Reverse Manager for events.Hours’s user

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

img

Accessor to the related object on the reverse side of a one-to-one relation.

In the example:

class Restaurant(Model):
    place = OneToOneField(Place, related_name='restaurant')

Place.restaurant is a ReverseOneToOneDescriptor instance.

is_complete

Returns false if the user’s profile is incomplete. The user will be constantly reminded to complete their profile.

is_lnl

Is an LNL member

laptoppasswordretrieval_set

Reverse Manager for devices.LaptopPasswordRetrieval’s user

lnl_contact

Reverse Manager for events.BaseEvent’s lnl_contact

locked

BooleanField(default=False)

logentry_set

Reverse Manager for admin.LogEntry’s user

mdc

CharField(verbose_name=”MDC”, max_length=32, blank=True, null=True)

mdc_name
meeting_set

Reverse Manager for meetings.Meeting’s attendance

mtgattachment_set

Reverse Manager for meetings.MtgAttachment’s author

multibillingemail_set

Reverse Manager for events.MultiBillingEmail’s email_to_users

name

User’s full name

nickname

CharField(verbose_name=”Nickname”, max_length=32, blank=True, null=True)

officehour_set

Reverse Manager for events.OfficeHour’s officer

onboarded

BooleanField(verbose_name=”Onboarding Complete”, default=False)

onboardingrecord_set

Reverse Manager for pages.OnboardingRecord’s user

onboardingscreen_set

Reverse Manager for pages.OnboardingScreen’s users

orgowner

Reverse Manager for events.Organization’s user_in_charge

orgs

Organizations the user belongs to

orgusers

Reverse Manager for events.Organization’s associated_users

owns

Organizations the user owns

phone

CharField(verbose_name=”Phone Number”, max_length=24, blank=True, null=True)

preferences

Accessor to the related object on the reverse side of a one-to-one relation.

In the example:

class Restaurant(Model):
    place = OneToOneField(Place, related_name='restaurant')

Place.restaurant is a ReverseOneToOneDescriptor instance.

projectionist

Accessor to the related object on the reverse side of a one-to-one relation.

In the example:

class Restaurant(Model):
    place = OneToOneField(Place, related_name='restaurant')

Place.restaurant is a ReverseOneToOneDescriptor instance.

pronouns

CharField(verbose_name=”Pronouns”, max_length=32, blank=True, null=True)

revision_set

Reverse Manager for reversion.Revision’s user

save(*args, **kwargs)[source]

Save the current instance. Override this in a subclass if you want to control the saving process.

The ‘force_insert’ and ‘force_update’ parameters can be used to insist that the “save” must be an SQL insert or update (or equivalent for non-SQL backends), respectively. Normally, they should not be set.

smsmessage_set

Reverse Manager for emails.SMSMessage’s user

spotify_accounts

Reverse Manager for spotify.SpotifyUser’s user

student_id

PositiveIntegerField(verbose_name=”Student ID”, blank=True, null=True)

stupidcat_set

Reverse Manager for data.StupidCat’s user

submitter

Reverse Manager for events.BaseEvent’s submitted_by

surveys

Reverse Manager for events.PostEventSurvey’s person

token_requests

Reverse Manager for api.TokenRequest’s user

trainings

Reverse Manager for members.Trainee’s person

trainings_entered

Reverse Manager for members.Training’s recorded_by

trainings_revoked

Reverse Manager for members.Trainee’s revoked_by

trainings_run

Reverse Manager for members.Training’s trainer

user_permissions

Reverse Manager for accounts.User’s user_permissions

verification_codes

Accessor to the related object on the reverse side of a one-to-one relation.

In the example:

class Restaurant(Model):
    place = OneToOneField(Place, related_name='restaurant')

Place.restaurant is a ReverseOneToOneDescriptor instance.

verification_events

Reverse Manager for events.OrgBillingVerificationEvent’s verified_by

workdayentries

Reverse Manager for events.Event2019’s workday_entered_by

wpibox

IntegerField(verbose_name=”WPI Box Number”, blank=True, null=True)

xfer_initiated

Reverse Manager for events.OrganizationTransfer’s initiator

xfer_new

Reverse Manager for events.OrganizationTransfer’s new_user_in_charge

xfer_old

Reverse Manager for events.OrganizationTransfer’s old_user_in_charge

class accounts.models.UserPreferences(*args, **kwargs)[source]

User-specific settings

Parameters:
  • id (AutoField) – Id (required)
  • user (OneToOneField to User) – User (required)
  • theme (CharField) – Theme (default=default)
  • rt_token (CharField) – Rt auth token
  • cc_add_subscriptions (MultiSelectField) – Cc add subscriptions (default=email)
  • cc_report_reminders (CharField) – Cc report reminders (default=email)
  • event_edited_notification_methods (CharField) – Event edited notification methods (default=email)
  • event_edited_field_subscriptions (MultiSelectField) – Event edited field subscriptions (default=[‘location’, ‘datetime_setup_complete’, ‘datetime_start’, ‘datetime_end’])
  • ignore_user_action (BooleanField) – Uncheck this to ignore notifications for actions triggered by the user (default=False)
  • meeting_invites (BooleanField) – Opt-in to receiving calendar invites for meetings (default=False)
  • meeting_invite_subscriptions (ManyToManyField to MeetingType) – Meeting invite subscriptions (required)
exception DoesNotExist
exception MultipleObjectsReturned
cc_add_subscriptions

CharField(max_length=11, blank=True, null=True, default=”email”, choices=[(‘email’, ‘Email’), (‘slack’, ‘Slack Notification’)])

cc_report_reminders

CharField(max_length=12, default=”email”, choices=[(‘email’, ‘Email’), (‘slack’, ‘Slack Notification’), (‘all’, ‘Both’)])

event_edited_field_subscriptions

CharField(max_length=149, default=[‘location’, ‘datetime_setup_complete’, ‘datetime_start’, ‘datetime_end’], choices=[(‘event_name’, ‘Event name’), (‘description’, ‘Description’), (‘location’, ‘Location’), (‘contact’, ‘Contact’), (‘lnl_contact’, ‘LNL contact’), (‘billing_org’, ‘Billing org’), (‘datetime_setup_complete’, ‘Datetime setup complete’), (‘datetime_start’, ‘Datetime start’), (‘datetime_end’, ‘Datetime end’), (‘internal_notes’, ‘Internal notes’), (‘billed_in_bulk’, ‘Billed in bulk’), (‘org’, ‘Client’)])

event_edited_notification_methods

CharField(max_length=12, default=”email”, choices=[(‘email’, ‘Email’), (‘slack’, ‘Slack Notification’), (‘all’, ‘Both’)])

get_cc_add_subscriptions_display()
get_cc_add_subscriptions_list()
get_cc_report_reminders_display(*, field=<django.db.models.fields.CharField: cc_report_reminders>)
get_event_edited_field_subscriptions_display()
get_event_edited_field_subscriptions_list()
get_event_edited_notification_methods_display(*, field=<django.db.models.fields.CharField: event_edited_notification_methods>)
get_theme_display(*, field=<django.db.models.fields.CharField: theme>)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

ignore_user_action

BooleanField(default=False, help_text=”Uncheck this to ignore notifications for actions triggered by the user”)

Ignore user action: Uncheck this to ignore notifications for actions triggered by the user

meeting_invite_subscriptions

Reverse Manager for accounts.UserPreferences’s meeting_invite_subscriptions

meeting_invites

BooleanField(default=False, help_text=”Opt-in to receiving calendar invites for meetings”)

Meeting invites: Opt-in to receiving calendar invites for meetings

objects = <django.db.models.manager.Manager object>
rt_token

CharField(verbose_name=”RT Auth Token”, max_length=256, blank=True, null=True)

theme

CharField(max_length=12, default=”default”, choices=[(‘default’, ‘Default’)])

user

OneToOneField(related_name=”preferences”, on_delete=CASCADE(), to= User)

user_id

Raw (integer) FK for user

accounts.models.officer_img_cleanup(sender, instance, **kwargs)[source]

When an instance of ProfilePhoto is deleted, delete the respective files as well.

Parameters:instance – A ProfilePhoto instance
accounts.models.path_and_rename(instance, filename)[source]

Determine path for storing officer headshots. Will rename with officer’s username.

Parameters:
  • instance – A ProfilePhoto instance
  • filename – The original name of the uploaded file
Returns:

New path to save file to


Views

class accounts.views.ActiveList(**kwargs)[source]

Lists active LNL members

accounts_disabled_column = False
name = 'Active List'
perms = ['accounts.view_member']
positions = False
queryset
class accounts.views.AllMembersList(**kwargs)[source]

Lists all LNL members

accounts_disabled_column = False
name = 'All Members List'
perms = ['accounts.view_member']
positions = False
queryset
class accounts.views.AlumniList(**kwargs)[source]

Lists LNL alumni

accounts_disabled_column = False
name = 'Alumni List'
perms = ['accounts.view_member']
positions = False
queryset
class accounts.views.AssociateList(**kwargs)[source]

Lists associate LNL members

accounts_disabled_column = False
name = 'Associate List'
perms = ['accounts.view_member']
positions = False
queryset
class accounts.views.AwayList(**kwargs)[source]

Lists LNL members on away status

accounts_disabled_column = False
name = 'Away List'
perms = ['accounts.view_member']
positions = False
queryset
class accounts.views.BaseUserList(**kwargs)[source]

Basic structure for user lists

context_object_name = 'users'
get_context_data(**kwargs)[source]

Get the context for this view.

model

alias of accounts.models.User

name = 'User List'
perms = ['accounts.view_user']
template_name = 'users.html'
class accounts.views.InactiveList(**kwargs)[source]

Lists inactive LNL members

accounts_disabled_column = True
name = 'Inactive List'
perms = ['accounts.view_member']
positions = False
queryset
class accounts.views.LimboList(**kwargs)[source]

Lists unassociated users

accounts_disabled_column = False
name = 'Users without Association'
positions = False
queryset
class accounts.views.MeDirectView(**kwargs)[source]

Redirects to a user’s profile page

get_redirect_url(*args, **kwargs)[source]

Return the URL redirect to. Keyword arguments from the URL pattern match generating the redirect request are provided as kwargs to this method.

class accounts.views.OfficerList(**kwargs)[source]

Lists LNL officers

accounts_disabled_column = False
name = 'Officer List'
perms = ['accounts.view_member']
positions = True
queryset
class accounts.views.PasswordSetView(**kwargs)[source]

Set a non-SSO login password

dispatch(request, pk, *args, **kwargs)[source]
form_valid(form)[source]

If the form is valid, redirect to the supplied URL.

get_context_data(**kwargs)[source]

Insert the form into the context dict.

get_form_class()[source]

Return the form class to use.

get_form_kwargs()[source]

Return the keyword arguments for instantiating the form.

get_success_url()[source]

Return the URL to redirect to after processing a valid form.

model

alias of accounts.models.User

msg = 'Set Non-SSO Login Password'
template_name = 'form_crispy.html'
user = None
class accounts.views.UserAddView(**kwargs)[source]

Add a new user manually (should rarely be used - LDAP does this for us)

form_class

alias of accounts.forms.UserAddForm

get_success_url()[source]

Return the URL to redirect to after processing a valid form.

model

alias of accounts.models.User

msg = 'Add User Manually'
perms = 'accounts.add_user'
template_name = 'form_crispy.html'
class accounts.views.UserDetailView(**kwargs)[source]

View user profile

get_context_data(**kwargs)[source]

Insert the single object into the context dict.

model

alias of accounts.models.User

perms = ['accounts.view_user']
slug_field = 'username'
slug_url_kwarg = 'username'
template_name = 'userdetail.html'
user_passes_test(request, *args, **kwargs)[source]
class accounts.views.UserUpdateView(**kwargs)[source]

Update user profile

form_class

alias of accounts.forms.UserEditForm

form_valid(form)[source]

If the form is valid, save the associated model.

get_context_data(**kwargs)[source]

Insert the form into the context dict.

get_success_url()[source]

Return the URL to redirect to after processing a valid form.

model

alias of accounts.models.User

perms = 'accounts.change_user'
slug_field = 'username'
slug_url_kwarg = 'username'
template_name = 'form_crispy_cbv.html'
user_passes_test(request, *args, **kwargs)[source]
accounts.views.application_scope_request(request)[source]

Prompt the user to allow applications connected to the LNLDB to interact with one another. Redirects to the application’s callback uri.

accounts.views.mdc(request)[source]

Displays a list of radio MDCs for LNL members

accounts.views.mdc_raw(request)[source]

Downloads a CSV file containing the radio MDCs of LNL members

accounts.views.officer_photos(request, pk=None)[source]

Update officer headshot (displayed on the main LNL website about page)

accounts.views.secretary_dashboard(request)[source]

Dashboard for the secretary. Lists important member counts used in voting and suggests users to activate, deactivate, associate, or take off away status.

accounts.views.shame(request)[source]

The LNL Crew Chief Report Hall of Shame. Tracks members who fail to complete event reports and lists the top 10 on a leaderboard.

accounts.views.smart_login(request)[source]

Intelligent signin handler. Presents the Sign in with Microsoft option if enabled. If already logged in, redirects to the requested page (can be used to check for an active session). Also checks for the Prefer SAML cookie and automatically attempts to log in via Microsoft SSO if present. Falls back on Django’s native login form otherwise.

accounts.views.user_preferences(request)[source]

Update a user’s account preferences (only visible to the user)


Forms

class accounts.forms.LoginForm(*args, **kwargs)[source]
base_fields = {'password': <django.forms.fields.CharField object>, 'username': <django.contrib.auth.forms.UsernameField object>}
declared_fields = {'password': <django.forms.fields.CharField object>, 'username': <django.contrib.auth.forms.UsernameField object>}
media
class accounts.forms.OfficerPhotoForm(*args, **kwargs)[source]
class Meta[source]
fields = ['img']
model

alias of accounts.models.ProfilePhoto

base_fields = {'img': <django.forms.fields.ImageField object>}
declared_fields = {}
media
class accounts.forms.SMSOptInForm(*args, **kwargs)[source]
class Meta[source]
fields = ('phone', 'carrier')
model

alias of accounts.models.User

base_fields = {'carrier': <django.forms.fields.ChoiceField object>, 'phone': <django.forms.fields.CharField object>}
declared_fields = {'carrier': <django.forms.fields.ChoiceField object>, 'phone': <django.forms.fields.CharField object>}
media
class accounts.forms.UserAddForm(*args, **kwargs)[source]
class Meta[source]
fields = ['username', 'email', 'first_name', 'last_name']
model

alias of accounts.models.User

base_fields = {'email': <django.forms.fields.EmailField object>, 'first_name': <django.forms.fields.CharField object>, 'last_name': <django.forms.fields.CharField object>, 'password1': <django.forms.fields.CharField object>, 'password2': <django.forms.fields.CharField object>, 'username': <django.forms.fields.CharField object>}
clean_password2()[source]
declared_fields = {'password1': <django.forms.fields.CharField object>, 'password2': <django.forms.fields.CharField object>}
error_messages = {'password_mismatch': "The two password fields didn't match."}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class accounts.forms.UserEditForm(*args, **kwargs)[source]
class FieldAccess[source]
edit_groups = <data.forms.FieldAccessLevel object>
edit_mdc = <data.forms.FieldAccessLevel object>
edit_student_id = <data.forms.FieldAccessLevel object>
hasperm = <data.forms.FieldAccessLevel object>
thisisme = <data.forms.FieldAccessLevel object>
unaffiliated = <data.forms.FieldAccessLevel object>
class Meta[source]
fields = ['username', 'email', 'first_name', 'last_name', 'nickname', 'pronouns', 'groups', 'addr', 'wpibox', 'mdc', 'phone', 'class_year', 'student_id', 'away_exp', 'carrier', 'title']
model

alias of accounts.models.User

base_fields = {'addr': <django.forms.fields.CharField object>, 'away_exp': <django.forms.fields.DateField object>, 'carrier': <django.forms.fields.TypedChoiceField object>, 'class_year': <django.forms.fields.IntegerField object>, 'email': <django.forms.fields.EmailField object>, 'first_name': <django.forms.fields.CharField object>, 'groups': <django.forms.models.ModelMultipleChoiceField object>, 'last_name': <django.forms.fields.CharField object>, 'mdc': <django.forms.fields.CharField object>, 'nickname': <django.forms.fields.CharField object>, 'phone': <django.forms.fields.CharField object>, 'pronouns': <django.forms.fields.CharField object>, 'student_id': <django.forms.fields.IntegerField object>, 'title': <django.forms.models.ModelChoiceField object>, 'username': <django.forms.fields.CharField object>, 'wpibox': <django.forms.fields.IntegerField object>}
clean_student_id()[source]
declared_fields = {'title': <django.forms.models.ModelChoiceField object>}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class accounts.forms.UserPreferencesForm(*args, **kwargs)[source]
class Meta[source]
fields = ('theme', 'cc_add_subscriptions', 'cc_report_reminders', 'event_edited_notification_methods', 'event_edited_field_subscriptions', 'ignore_user_action', 'meeting_invites', 'meeting_invite_subscriptions')
layout = [('Text', '<div class="ui secondary segment"><h4 class="ui dividing header">Appearance</h4>'), ('Field', 'theme'), ('Text', '</div><div class="ui secondary segment nobullet"><h4 class="ui dividing header">Communications</h4><div class="ui styled accordion" style="width: 100%"><div class="title"><i class="dropdown icon"></i>LNL News</div><div class="content"><p class="ui help">General club information, advertisements and meeting notices. This content will typically be sent to the <em>lnl-news@wpi.edu</em> email alias. You may opt out of receiving these messages at any time through Outlook.</p>'), ('Text', '<a href="https://lnl.wpi.edu/legal/opt-out/" class="ui blue basic button">Opt out</a>'), ('Text', '</div><div class="title"><i class="dropdown icon"></i>Crew Chief Add Notifications</div><div class="content"><p class="ui help">Receive a notification whenever you are added as a Crew Chief for a new event.</p>'), ('Field', 'cc_add_subscriptions'), ('Text', '</div><div class="title"><i class="dropdown icon"></i>Crew Chief Report Reminders</div><div class="content"><p class="ui help">Receive reminders for missing crew chief reports.</p>'), ('Field', 'cc_report_reminders'), ('Text', '</div><div class="title"><i class="dropdown icon"></i>Crew Chief Needed Notifications</div><div class="content"><p class="ui help">Receive an alert whenever the VP needs crew chiefs to run an event.</p>'), ('Field', 'cc_needed_subscriptions'), ('Text', '</div><div class="title"><i class="dropdown icon"></i>Event Edit Notifications</div><div class="content"><p class="ui help">Receive alerts whenever details for an event you are involved with have changed.</p>'), ('Field', 'event_edited_notification_methods'), ('Text', '<br><hr style=\'border: 1px dashed gray\'><br><p class"ui help">Notify me of changes to any of the following fields:<br><br><span class="ui label">Location</span><span class="ui label">Event Setup Time</span><span class="ui label">Event Start</span><span class="ui label">Event End</span></p>'), ('Field', 'event_edited_field_subscriptions'), ('Text', '</div><div class="title"><i class="dropdown icon"></i>Web Service Notifications</div><div class="content"><p class="ui help">General account and system-wide notices. You may not unsubscribe from these messages.</p>'), ('Field', 'srv'), ('Text', '</div></div><br><div class="ui styled accordion" style="width: 100%"><div class="title"><i class="dropdown icon"></i>Calendar Invites - Meetings</div><div class="content">'), ('Field', 'meeting_invites'), ('Text', '<br><hr style=\'border: 1px dashed gray\'><p class"ui help">Automatically send me invites for the following types of meetings:<br>'), ('Field', 'meeting_invite_subscriptions'), ('Text', '</div></div><div class="ui segment">'), ('Field', 'ignore_user_action'), ('Text', '</div></div><div class="ui secondary segment"><h4 class="ui dividing header">Request Tracker</h4>'), ('Text', '<a href="/support/connect/rt/" class="ui green basic button">Connect Account</a>'), ('Text', '</div>')]
model

alias of accounts.models.UserPreferences

base_fields = {'cc_add_subscriptions': <django.forms.fields.MultipleChoiceField object>, 'cc_needed_subscriptions': <django.forms.fields.MultipleChoiceField object>, 'cc_report_reminders': <django.forms.fields.ChoiceField object>, 'event_edited_field_subscriptions': <django.forms.fields.MultipleChoiceField object>, 'event_edited_notification_methods': <django.forms.fields.ChoiceField object>, 'ignore_user_action': <django.forms.fields.BooleanField object>, 'meeting_invite_subscriptions': <django.forms.models.ModelMultipleChoiceField object>, 'meeting_invites': <django.forms.fields.BooleanField object>, 'srv': <django.forms.fields.MultipleChoiceField object>, 'theme': <django.forms.fields.TypedChoiceField object>}
declared_fields = {'cc_add_subscriptions': <django.forms.fields.MultipleChoiceField object>, 'cc_needed_subscriptions': <django.forms.fields.MultipleChoiceField object>, 'cc_report_reminders': <django.forms.fields.ChoiceField object>, 'event_edited_field_subscriptions': <django.forms.fields.MultipleChoiceField object>, 'event_edited_notification_methods': <django.forms.fields.ChoiceField object>, 'ignore_user_action': <django.forms.fields.BooleanField object>, 'meeting_invite_subscriptions': <django.forms.models.ModelMultipleChoiceField object>, 'meeting_invites': <django.forms.fields.BooleanField object>, 'srv': <django.forms.fields.MultipleChoiceField object>}
media

Data

This module handles various external or otherwise miscellaneous data sources.

Models

class data.models.Extension(*args, **kwargs)[source]

Application registered to use the API

Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – Name (required)
  • developer (CharField) – Developer (required)
  • description (TextField) – Description (required)
  • icon (ImageField) – Icon
  • api_key (CharField) – Api key (required)
  • enabled (BooleanField) – Enabled (required)
  • registered (DateTimeField) – Registered (required)
  • last_modified (DateTimeField) – Last modified (required)
  • users (ManyToManyField to User) – Users (required)
exception DoesNotExist
exception MultipleObjectsReturned
api_key

CharField(verbose_name=”API Key”, max_length=36)

description

TextField()

developer

CharField(max_length=64)

enabled

BooleanField()

get_next_by_last_modified(*, field=<django.db.models.fields.DateTimeField: last_modified>, is_next=True, **kwargs)
get_next_by_registered(*, field=<django.db.models.fields.DateTimeField: registered>, is_next=True, **kwargs)
get_previous_by_last_modified(*, field=<django.db.models.fields.DateTimeField: last_modified>, is_next=False, **kwargs)
get_previous_by_registered(*, field=<django.db.models.fields.DateTimeField: registered>, is_next=False, **kwargs)
icon

Just like the FileDescriptor, but for ImageFields. The only difference is assigning the width/height to the width_field/height_field, if appropriate.

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

last_modified

DateTimeField(auto_now=True)

name

CharField(max_length=120)

objects = <django.db.models.manager.Manager object>
registered

DateTimeField(auto_now_add=True)

users

Reverse Manager for data.Extension’s users

class data.models.GlobalPerms(id)[source]
Parameters:id (AutoField) – Id (required)
exception DoesNotExist
exception MultipleObjectsReturned
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
class data.models.Notification(*args, **kwargs)[source]

Passive site notifications - accessible through the API

Parameters:
  • id (AutoField) – Id (required)
  • title (CharField) – Title (required)
  • message (TextField) – Message (required)
  • format (CharField) – Format (required)
  • type (CharField) – Type (required)
  • dismissible (BooleanField) – Dismissible (default=False)
  • target (CharField) – To target a specific page, include the full pathname (i.e. ‘/services/lighting.html’ or ‘/events/’). To target a directory, include only the directory name (i.e. ‘events’). For a sitewide notification, enter ‘All’. (required)
  • expires (DateTimeField) – Expires (required)
exception DoesNotExist
exception MultipleObjectsReturned
dismissible

BooleanField(default=False)

expires

DateTimeField()

format

CharField(max_length=12, choices=[(‘alert’, ‘Alert’), (‘notification’, ‘Notification’)])

get_format_display(*, field=<django.db.models.fields.CharField: format>)
get_next_by_expires(*, field=<django.db.models.fields.DateTimeField: expires>, is_next=True, **kwargs)
get_previous_by_expires(*, field=<django.db.models.fields.DateTimeField: expires>, is_next=False, **kwargs)
get_type_display(*, field=<django.db.models.fields.CharField: type>)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

message

TextField(max_length=500)

objects = <django.db.models.manager.Manager object>
target

CharField(max_length=200, help_text=”To target a specific page, include the full pathname (i.e. ‘/services/lighting.html’ or ‘/events/’). To target a directory, include only the directory name (i.e. ‘events’). For a sitewide notification, enter ‘All’.”)

Target: To target a specific page, include the full pathname (i.e. ‘/services/lighting.html’ or ‘/events/’). To target a directory, include only the directory name (i.e. ‘events’). For a sitewide notification, enter ‘All’.

title

CharField(max_length=128)

type

CharField(max_length=8, choices=[(‘info’, ‘Info’), (‘advisory’, ‘Advisory’), (‘warning’, ‘Warning’)])

class data.models.ResizedRedirect(*args, **kwargs)[source]

Custom redirect (configured from the admin site)

Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – User friendly name
  • site (ForeignKey to Site) – Site (required)
  • old_path (CharField) – This should be an absolute path, excluding the domain name. Example: ‘/events/search/’. (required)
  • new_path (CharField) – This can be either an absolute path (as above) or a full URL starting with ‘http://’. (required)
  • sitemap (BooleanField) – Include in sitemap (default=False)
exception DoesNotExist
exception MultipleObjectsReturned
clean()[source]

Hook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

name

CharField(max_length=64, blank=True, null=True, help_text=”User friendly name”)

Name: User friendly name

new_path

CharField(verbose_name=redirect to, max_length=200, blank=True, help_text=This can be either an absolute path (as above) or a full URL starting with ‘http://’.)

Redirect to: This can be either an absolute path (as above) or a full URL starting with ‘http://’.

objects = <django.db.models.manager.Manager object>
old_path

CharField(verbose_name=redirect from, max_length=190, db_index=True, help_text=This should be an absolute path, excluding the domain name. Example: ‘/events/search/’.)

Redirect from: This should be an absolute path, excluding the domain name. Example: ‘/events/search/’.

site

ForeignKey(verbose_name=site, on_delete=CASCADE(), to= Site)

site_id

Raw (integer) FK for site

sitemap

BooleanField(verbose_name=”Include in Sitemap”, default=False)

class data.models.StupidCat(*args, **kwargs)[source]

For logging when a user goes somewhere they shouldn’t be going

Parameters:
  • id (AutoField) – Id (required)
  • user (ForeignKey to User) – User
  • user_ip (GenericIPAddressField) – User ip (required)
  • requested_uri (CharField) – Requested uri (required)
  • timestamp (DateTimeField) – Timestamp (required)
exception DoesNotExist
exception MultipleObjectsReturned
get_next_by_timestamp(*, field=<django.db.models.fields.DateTimeField: timestamp>, is_next=True, **kwargs)
get_previous_by_timestamp(*, field=<django.db.models.fields.DateTimeField: timestamp>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
requested_uri

CharField(max_length=512)

timestamp

DateTimeField(auto_now_add=True)

user

ForeignKey(blank=True, null=True, on_delete=CASCADE(), to= User)

user_id

Raw (integer) FK for user

user_ip

GenericIPAddressField()


Views

data.views.err403(request, *args, **kwargs)[source]
data.views.err404(request, *args, **kwargs)[source]
data.views.err500(request, *args, **kwargs)[source]
data.views.maintenance(request)[source]

Display maintenance page

data.views.search(request)[source]

New search tool using Watson

data.views.serve_file(request, att_file, forced_name=None)[source]
data.views.workorderwizard_findprevious(request)[source]

Checks for previous events submitted by a user in the last 18 months

Returns:A previous event; 402 status code if nothing is found; 422 status code if processing fails; 401 status code if unauthenticated
data.views.workorderwizard_load(request)[source]

Endpoint the workorder wizard uses to load initial data.

Returns:Dictionary of event locations, organizations, and user details; 401 status code if not authenticated
data.views.workorderwizard_submit(request)[source]

Handles submission of workorder from workorder wizard.

Returns:URL to event page on success; 422 status code if processing fails; 401 status code if unauthenticated

Forms

class data.forms.DynamicFieldContainer(*fields)[source]
render(form, form_style, context, template_pack=<SimpleLazyObject: 'bootstrap3'>)[source]
class data.forms.FieldAccessForm(request_user, *args, **kwargs)[source]

This class will grant or deny access to individual fields according to simple rules.

Example:

class MyForm(FieldAccessForm):
class FieldAccess:
staff = FieldAccessLevel(lambda u, i: u.is_staff,
enable = (‘field1’, ‘field2’), exclude = (‘field3’,))
base_fields = {}
declared_fields = {}
media
class data.forms.FieldAccessLevel(rule, enable=None, exclude=None)[source]

Represents an access level for a form.


Decorators

data.decorators.process_in_thread(method)[source]

Use this decorator to indicate that a method should be processed on a separate thread.

WARNING: Refrain from interacting with the database while using this decorator (i.e. no read / write). If you do access the database, be sure to call connection.close() (from django.db import connection) at the end of the method.

Devices

This module is used to manage information related to LNL’s managed devices (i.e. Laptops).

Models

class devices.models.ConfigurationProfile(*args, **kwargs)[source]

This class defines metadata for a given macOS configuration profile. The core profile data is stored in a separate JSON file.

Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – Name (required)
  • profile (FilePathField) – Profile (required)
  • scope (CharField) – Scope (default=System)
  • created_on (DateTimeField) – Created on (required)
  • last_modified (DateTimeField) – Last modified (required)
  • pending_install (ManyToManyField to Laptop) – Pending install (required)
  • installed (ManyToManyField to Laptop) – Installed (required)
exception DoesNotExist
exception MultipleObjectsReturned
created_on

DateTimeField(auto_now_add=True)

get_next_by_created_on(*, field=<django.db.models.fields.DateTimeField: created_on>, is_next=True, **kwargs)
get_next_by_last_modified(*, field=<django.db.models.fields.DateTimeField: last_modified>, is_next=True, **kwargs)
get_previous_by_created_on(*, field=<django.db.models.fields.DateTimeField: created_on>, is_next=False, **kwargs)
get_previous_by_last_modified(*, field=<django.db.models.fields.DateTimeField: last_modified>, is_next=False, **kwargs)
get_scope_display(*, field=<django.db.models.fields.CharField: scope>)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

install_records

Reverse Manager for devices.InstallationRecord’s profile

installed

Reverse Manager for devices.ConfigurationProfile’s installed

last_modified

DateTimeField(auto_now=True)

name

CharField(max_length=100)

objects = <django.db.models.manager.Manager object>
pending_install

Reverse Manager for devices.ConfigurationProfile’s pending_install

profile

FilePathField(path=”/home/docs/checkouts/readthedocs.org/user_builds/lnldb/checkouts/latest/runtime/media/profiles”, match=”.*.json$”)

scope

CharField(max_length=6, default=”System”, choices=[(‘System’, ‘System’), (‘User’, ‘User’)])

class devices.models.InstallationRecord(*args, **kwargs)[source]

Used to log when managed resources were last installed on a device

Parameters:
  • id (AutoField) – Id (required)
  • profile (ForeignKey to ConfigurationProfile) – Profile
  • app (ForeignKey to MacOSApp) – App
  • device (ForeignKey to Laptop) – Device (required)
  • version (CharField) – Version
  • installed_on (DateTimeField) – Installed on (required)
  • expires (DateTimeField) – Expires
  • active (BooleanField) – Active (default=True)
exception DoesNotExist
exception MultipleObjectsReturned
active

BooleanField(default=True)

app

ForeignKey(blank=True, null=True, related_name=”install_records”, on_delete=CASCADE(), to= MacOSApp)

app_id

Raw (integer) FK for app

device

ForeignKey(related_name=”install_records”, on_delete=CASCADE(), to= Laptop)

device_id

Raw (integer) FK for device

expires

DateTimeField(blank=True, null=True)

get_next_by_installed_on(*, field=<django.db.models.fields.DateTimeField: installed_on>, is_next=True, **kwargs)
get_previous_by_installed_on(*, field=<django.db.models.fields.DateTimeField: installed_on>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

installed_on

DateTimeField(auto_now_add=True)

objects = <django.db.models.manager.Manager object>
profile

ForeignKey(blank=True, null=True, related_name=”install_records”, on_delete=CASCADE(), to= ConfigurationProfile)

profile_id

Raw (integer) FK for profile

version

CharField(max_length=36, blank=True, null=True)

class devices.models.Laptop(*args, **kwargs)[source]

Represents one of LNL’s laptops

Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – Name (required)
  • description (TextField) – Description (required)
  • serial (CharField) – Serial
  • asset_tag (CharField) – Asset tag
  • api_key_hash (CharField) – SHA-256 hash of the API key that the laptop uses to communicate with the database (required)
  • user_password (CharField) – User password (required)
  • admin_password (CharField) – Admin password (required)
  • last_checkin (DateTimeField) – Last checkin
  • last_ip (CharField) – Last network ip address
  • mdm_enrolled (BooleanField) – Enrolled in mdm (default=False)
  • retired (BooleanField) – Retired (default=False)
exception DoesNotExist
exception MultipleObjectsReturned
admin_password

CharField(max_length=64)

api_key_hash

CharField(verbose_name=”API key hash”, max_length=64, db_index=True, help_text=”SHA-256 hash of the API key that the laptop uses to communicate with the database”)

Api key hash: SHA-256 hash of the API key that the laptop uses to communicate with the database

apps_installed

Reverse Manager for devices.MacOSApp’s installed

apps_pending

Reverse Manager for devices.MacOSApp’s pending_install

apps_remove

Reverse Manager for devices.MacOSApp’s pending_removal

asset_tag

CharField(max_length=25, blank=True, null=True)

description

TextField(blank=True)

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

install_records

Reverse Manager for devices.InstallationRecord’s device

installed

Reverse Manager for devices.ConfigurationProfile’s installed

last_checkin

DateTimeField(blank=True, null=True)

last_ip

CharField(verbose_name=”Last Network IP Address”, max_length=15, blank=True, null=True)

mdm_enrolled

BooleanField(verbose_name=”Enrolled in MDM”, default=False)

name

CharField(max_length=20)

objects = <django.db.models.manager.Manager object>
password_retrievals

Reverse Manager for devices.LaptopPasswordRetrieval’s laptop

password_rotations

Reverse Manager for devices.LaptopPasswordRotation’s laptop

pending

Reverse Manager for devices.ConfigurationProfile’s pending_install

retired

BooleanField(default=False)

serial

CharField(max_length=12, blank=True, null=True)

user_password

CharField(max_length=64)

class devices.models.LaptopPasswordRetrieval(*args, **kwargs)[source]

Used to keep track of when users access the laptop passwords

Parameters:
  • id (AutoField) – Id (required)
  • timestamp (DateTimeField) – Timestamp (required)
  • laptop (ForeignKey to Laptop) – Laptop (required)
  • user (ForeignKey to User) – User (required)
  • admin (BooleanField) – Admin (required)
exception DoesNotExist
exception MultipleObjectsReturned
admin

BooleanField()

get_next_by_timestamp(*, field=<django.db.models.fields.DateTimeField: timestamp>, is_next=True, **kwargs)
get_previous_by_timestamp(*, field=<django.db.models.fields.DateTimeField: timestamp>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

laptop

ForeignKey(related_name=”password_retrievals”, on_delete=CASCADE(), to= Laptop)

laptop_id

Raw (integer) FK for laptop

objects = <django.db.models.manager.Manager object>
timestamp

DateTimeField(auto_now_add=True)

user

ForeignKey(on_delete=PROTECT(), to= User)

user_id

Raw (integer) FK for user

class devices.models.LaptopPasswordRotation(*args, **kwargs)[source]

Used to keep track of when passwords are rotated on LNL’s MacBooks

Parameters:
  • id (AutoField) – Id (required)
  • timestamp (DateTimeField) – Timestamp (required)
  • laptop (ForeignKey to Laptop) – Laptop (required)
exception DoesNotExist
exception MultipleObjectsReturned
get_next_by_timestamp(*, field=<django.db.models.fields.DateTimeField: timestamp>, is_next=True, **kwargs)
get_previous_by_timestamp(*, field=<django.db.models.fields.DateTimeField: timestamp>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

laptop

ForeignKey(related_name=”password_rotations”, on_delete=CASCADE(), to= Laptop)

laptop_id

Raw (integer) FK for laptop

objects = <django.db.models.manager.Manager object>
timestamp

DateTimeField(auto_now_add=True)

class devices.models.MacOSApp(*args, **kwargs)[source]

Used to keep track of managed applications for LNL’s MacBooks

Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – Name (required)
  • identifier (CharField) – Homebrew Identifier
  • version (CharField) – Version
  • description (TextField) – Description
  • developer (CharField) – Developer
  • developer_website (URLField) – Developer website
  • requires_license (BooleanField) – Requires license (default=False)
  • managed (BooleanField) – Available in msc (default=False)
  • merged_into (ForeignKey to MacOSApp) – Mergedapps
  • pending_install (ManyToManyField to Laptop) – Pending install (required)
  • pending_removal (ManyToManyField to Laptop) – Pending removal (required)
  • installed (ManyToManyField to Laptop) – Installed (required)
exception DoesNotExist
exception MultipleObjectsReturned
description

TextField(blank=True, null=True)

developer

CharField(max_length=64, blank=True, null=True)

developer_website

CharField(blank=True, null=True)

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

identifier

CharField(max_length=64, blank=True, null=True, help_text=”Homebrew Identifier”)

Identifier: Homebrew Identifier

install_records

Reverse Manager for devices.InstallationRecord’s app

installed

Reverse Manager for devices.MacOSApp’s installed

macosapp_set

Reverse Manager for devices.MacOSApp’s merged_into

managed

BooleanField(verbose_name=”Available in MSC”, default=False)

merged_into

ForeignKey(verbose_name=”mergedapps”, blank=True, null=True, on_delete=SET_NULL(), to= MacOSApp)

merged_into_id

Raw (integer) FK for merged_into

name

CharField(max_length=128)

objects = <django.db.models.manager.Manager object>
pending_install

Reverse Manager for devices.MacOSApp’s pending_install

pending_removal

Reverse Manager for devices.MacOSApp’s pending_removal

requires_license

BooleanField(default=False)

version

CharField(max_length=36, blank=True, null=True)


Views

devices.views.add_app(request)[source]

Administrators can use this page to add new managed applications. Non-admin users will have the option to request new software. Requests from non-admins will trigger a notification for the Webmaster.

devices.views.app_list(request)[source]

Lists all the applications available through Homebrew

devices.views.complete_enrollment(request, pk)[source]

Launched once the installation process is completed on a new device. Prompts the user for additional administrative details such as the asset tag number to complete the enrollment process.

Parameters:pk – Primary key of device
devices.views.dock_app_list(data)[source]

Used in generating macOS configuration profiles. Generates a dictionary with details about applications that should be added to the Dock.

Parameters:data – Form data (Dictionary)
Returns:Dictionary - {‘name’: <string>, ‘path’: <string>}
devices.views.fw_app_list(data)[source]

Used in generating macOS configuration profiles. Generates a dictionary used in configuring Firewall settings.

Parameters:data – Form data (Dictionary)
Returns:Dictionary - {‘bundle_id’: <string>, ‘allowed’: <boolean>}
devices.views.generate_ids()[source]

Generates UUIDs for each of the profile’s payloads.

Returns:Dictionary of payload identifiers
devices.views.generate_profile(request, pk=0)[source]

Create or edit a macOS configuration profile

Parameters:pk – Primary key of configuration profile (Optional)
devices.views.get_payloads(data)[source]

Generates a dictionary which specifies which payloads are active in a given profile and what their current version numbers are.

Parameters:data – Form data (Dictionary)
Returns:Dictionary of payload versions
devices.views.get_profile_metadata(config, timestamp)[source]

Retrieve additional metadata from profile data

Parameters:
  • config – Configuration Profile object
  • timestamp – Timestamp at time of install
Returns:

Dictionary with profile metadata - {‘expires’: <datetime>, ‘version’: <string>}

devices.views.handle_expired_profiles()[source]

Checks for expired profiles and updates listings accordingly

devices.views.install_client(request)[source]

Displays an agreement that the user must agree to before they can download the MDM Client installer

devices.views.install_confirmation(request)[source]

Endpoint for accepting receipt of install. Managed devices should contact this endpoint anytime new resources are installed.

Returns:JSON - {‘status’: 200}
devices.views.laptop_admin_password(request, id)[source]

Retrieve the admin password for one of the laptops

Parameters:id – Primary key of laptop
devices.views.laptop_history(request, id)[source]

View a history of password retrievals and rotations for a given laptop

Parameters:id – Primary key of laptop
devices.views.laptop_user_password(request, id)[source]

Retrieve the LNL user password for one of the laptops

Parameters:id – Primary key of laptop
devices.views.laptops_list(request)[source]

View a list of LNL’s laptops

Assign managed apps to a device. If a primary key value for device is supplied, a list of managed applications will be displayed. The user can then select which applications to assign to the respective device. The opposite is true when a primary key value is supplied for app.

Parameters:
  • device – Primary key of device (Optional)
  • app – Primary key of managed application (Optional)

Assign configuration profiles to a device. If a primary key value for device is supplied, a list of profiles will be displayed. The user can then select which profiles to assign to the respective device. The opposite is true when a primary key value is supplied for profile.

Parameters:
  • device – Primary key of device (Optional)
  • profile – Primary key of configuration profile (Optional)
devices.views.list_app_devices(request, pk)[source]

List all devices linked to a specific app

Parameters:pk – Primary key of managed application
devices.views.list_apps(request, pk=0)[source]

If a value is provided for pk, this will list all the managed applications assigned to the respective device. Otherwise this will list all the managed apps under the MDM.

Parameters:pk – Primary key of device (Optional)
devices.views.list_profiles(request, pk=0)[source]

When given a pk value, this view will list all the configuration profiles for a given device. When pk is not supplied, the view will list all the profiles in the MDM.

Parameters:pk – Primary key of device (Optional)
devices.views.load_ids(data)[source]

Reassembles payload identifiers. This is necessary because the MDM does not store the full payload identifiers with the profile data.

Parameters:data – Dictionary of payload identifiers
Returns:Dictionary of payload identifiers
devices.views.logs(request)[source]

Displays logs detailing what was installed on what devices and when

devices.views.mdm_checkin(request)[source]

Endpoint for device check-in. Managed devices will check in each time a new user logs onto the device.

Returns:JSON - If resources are pending install, includes the identifiers needed for the client to fetch and install them. Returns {‘status’: 200} otherwise.
devices.views.mdm_enroll(request)[source]

Endpoint for starting the enrollment process. Must be contacted directly by the device being enrolled.

Returns:Relative path to the link to complete the enrollment process (if client token is valid)
devices.views.mdm_list(request)[source]

MDM Console Homepage

devices.views.merge_app(request, pk)[source]

Page for merging two app records together. This is helpful when we want to hide duplicates.

Parameters:pk – Primary key of the managed application to be merged
devices.views.mobile_config(request, profile_id, action='Install')[source]

Endpoint for generating and downloading a macOS configuration profile. The request must include the MDM Client token for authentication purposes.

If action is set to Uninstall, the resulting file will cause existing copies of the profile to be removed from the device.

Parameters:
  • profile_id – Primary key of configuration profile
  • action – Either ‘Install’ or ‘Uninstall’
devices.views.profile_devices(request, pk)[source]

List all devices that are linked to a given profile

Parameters:pk – Primary key of configuration profile
devices.views.refresh_managed_software_status()[source]

Checks the Munki catalogs to retrieve the latest managed software lists

devices.views.reload_from_munki(request, pk)[source]

Refresh an application’s record with data from the Munki catalog

Parameters:pk – The primary key of the application to refresh data for
devices.views.removal_password(request)[source]

Displays the password that can be used to manually remove configuration profiles from managed devices

devices.views.remove_app(request, app, device=0)[source]

If a primary key value is supplied for both the device and app, the user will be able to remove the assignment between the managed application and that particular device. If only the app is provided, all device assignments for the application will be removed and the app will no longer be available to devices under the MDM.

Parameters:
  • app – Primary key of managed application
  • device – Primary key of device (Optional)
devices.views.remove_device(request, pk)[source]

Removes a device from the MDM. Presents warnings and instructions for how to complete the operation correctly.

Parameters:pk – Primary key of device
devices.views.remove_profile(request, profile, device=0)[source]

If a primary key value is supplied for both the device and profile, the user will be able to remove the assignment between the profile and that particular device. If only the profile is provided, all device assignments for the profile will be removed and the profile data will be deleted. In both cases, two options will be presented to the user:

1.) Mark the profile as removed (if the profile had already been removed manually)

2.) Instruct the MDM to remove the profile automatically at the next checkin

Parameters:
  • profile – Primary key of configuration profile
  • device – Primary key of device (Optional)
devices.views.rotate_passwords(request)[source]

Endpoint for updating the MacBook passwords once they’ve been rotated.

Returns:The old passwords so the MacBooks can complete the rotation
devices.views.update_app_info(request, pk)[source]

Update the metadata for a managed application.

Parameters:pk – Primary key of managed application
devices.views.view_app(request, pk)[source]

Details page for a specific managed application

Parameters:pk – Primary key of managed application

Forms

class devices.forms.AppMergeForm(*args, **kwargs)[source]
base_fields = {'options': <django.forms.fields.ChoiceField object>}
declared_fields = {'options': <django.forms.fields.ChoiceField object>}
media
class devices.forms.AssignmentForm(*args, **kwargs)[source]
base_fields = {'options': <django.forms.fields.MultipleChoiceField object>}
declared_fields = {'options': <django.forms.fields.MultipleChoiceField object>}
media
class devices.forms.ClientForm(*args, **kwargs)[source]
base_fields = {}
declared_fields = {}
media
class devices.forms.EnrollmentForm(*args, **kwargs)[source]
class Meta[source]
fields = ('name', 'serial', 'asset_tag', 'user_password', 'admin_password')
model

alias of devices.models.Laptop

base_fields = {'admin_password': <django.forms.fields.CharField object>, 'asset_tag': <django.forms.fields.CharField object>, 'name': <django.forms.fields.CharField object>, 'serial': <django.forms.fields.CharField object>, 'user_password': <django.forms.fields.CharField object>}
declared_fields = {'asset_tag': <django.forms.fields.CharField object>}
media
class devices.forms.NewAppForm(*args, **kwargs)[source]
class FieldAccess[source]
can_edit = <data.forms.FieldAccessLevel object>
can_request = <data.forms.FieldAccessLevel object>
class Meta[source]
fields = ['name', 'developer', 'version', 'description', 'developer_website']
model

alias of devices.models.MacOSApp

base_fields = {'description': <django.forms.fields.CharField object>, 'developer': <django.forms.fields.CharField object>, 'developer_website': <django.forms.fields.URLField object>, 'name': <django.forms.fields.CharField object>, 'version': <django.forms.fields.CharField object>}
declared_fields = {}
media
class devices.forms.ProfileForm(*args, **kwargs)[source]
base_fields = {'ac_display_timer': <django.forms.fields.IntegerField object>, 'ac_power_failure': <django.forms.fields.BooleanField object>, 'ac_system_timer': <django.forms.fields.IntegerField object>, 'ac_wake_lan': <django.forms.fields.BooleanField object>, 'ac_wake_modem': <django.forms.fields.BooleanField object>, 'ad_tracking': <django.forms.fields.BooleanField object>, 'admin_install': <django.forms.fields.BooleanField object>, 'alpha': <django.forms.fields.BooleanField object>, 'anim': <django.forms.fields.BooleanField object>, 'anim_immutable': <django.forms.fields.BooleanField object>, 'app_adoption': <django.forms.fields.BooleanField object>, 'app_auto': <django.forms.fields.BooleanField object>, 'app_name_0': <django.forms.fields.CharField object>, 'app_path_0': <django.forms.fields.CharField object>, 'apple_music': <django.forms.fields.BooleanField object>, 'auto_backup': <django.forms.fields.BooleanField object>, 'auto_check': <django.forms.fields.BooleanField object>, 'auto_download': <django.forms.fields.BooleanField object>, 'auto_remove': <django.forms.fields.ChoiceField object>, 'autofill_address': <django.forms.fields.BooleanField object>, 'autofill_forms': <django.forms.fields.BooleanField object>, 'autohide': <django.forms.fields.BooleanField object>, 'autohide_immutable': <django.forms.fields.BooleanField object>, 'backup_size': <django.forms.fields.IntegerField object>, 'backup_sys': <django.forms.fields.BooleanField object>, 'backup_url': <django.forms.fields.CharField object>, 'backup_volumes': <django.forms.fields.BooleanField object>, 'battery_display_timer': <django.forms.fields.IntegerField object>, 'battery_power_failure': <django.forms.fields.BooleanField object>, 'battery_system_timer': <django.forms.fields.IntegerField object>, 'battery_wake_lan': <django.forms.fields.BooleanField object>, 'battery_wake_modem': <django.forms.fields.BooleanField object>, 'block_all': <django.forms.fields.BooleanField object>, 'caching': <django.forms.fields.BooleanField object>, 'cloud_address': <django.forms.fields.BooleanField object>, 'cloud_bookmarks': <django.forms.fields.BooleanField object>, 'cloud_cal': <django.forms.fields.BooleanField object>, 'cloud_doc_sync': <django.forms.fields.BooleanField object>, 'cloud_docs_desk': <django.forms.fields.BooleanField object>, 'cloud_keychain': <django.forms.fields.BooleanField object>, 'cloud_mail': <django.forms.fields.BooleanField object>, 'cloud_notes': <django.forms.fields.BooleanField object>, 'cloud_reminders': <django.forms.fields.BooleanField object>, 'command_click': <django.forms.fields.BooleanField object>, 'complexity': <django.forms.fields.IntegerField object>, 'config_install': <django.forms.fields.BooleanField object>, 'console': <django.forms.fields.BooleanField object>, 'content_immutable': <django.forms.fields.BooleanField object>, 'cookies': <django.forms.fields.ChoiceField object>, 'default_browser': <django.forms.fields.BooleanField object>, 'description': <django.forms.fields.CharField object>, 'desktop_path': <django.forms.fields.CharField object>, 'desktop_version': <django.forms.fields.IntegerField object>, 'developers_policy': <django.forms.fields.BooleanField object>, 'device_backups': <django.forms.fields.BooleanField object>, 'diagnostics': <django.forms.fields.BooleanField object>, 'diagnostics_version': <django.forms.fields.IntegerField object>, 'disable_airdrop': <django.forms.fields.BooleanField object>, 'disable_assistant': <django.forms.fields.BooleanField object>, 'disable_autounlock': <django.forms.fields.BooleanField object>, 'disable_beta': <django.forms.fields.BooleanField object>, 'disable_camera': <django.forms.fields.BooleanField object>, 'disable_context': <django.forms.fields.BooleanField object>, 'disable_handoff': <django.forms.fields.BooleanField object>, 'disable_password_change': <django.forms.fields.BooleanField object>, 'disable_screenshot': <django.forms.fields.BooleanField object>, 'disable_sleep': <django.forms.fields.BooleanField object>, 'disable_touchid': <django.forms.fields.BooleanField object>, 'disabled_panes': <django.forms.fields.MultipleChoiceField object>, 'disallow_notifications': <django.forms.fields.BooleanField object>, 'display_name': <django.forms.fields.CharField object>, 'dock_version': <django.forms.fields.IntegerField object>, 'downloads_clear': <django.forms.fields.ChoiceField object>, 'downloads_path': <django.forms.fields.CharField object>, 'ds_store': <django.forms.fields.BooleanField object>, 'empty_trash': <django.forms.fields.BooleanField object>, 'enable_protection': <django.forms.fields.BooleanField object>, 'enabled_panes': <django.forms.fields.MultipleChoiceField object>, 'energy_version': <django.forms.fields.IntegerField object>, 'extra_dock': <django.forms.fields.IntegerField object>, 'extra_firewall': <django.forms.fields.IntegerField object>, 'filename': <django.forms.fields.CharField object>, 'filevault': <django.forms.fields.BooleanField object>, 'filevault_version': <django.forms.fields.IntegerField object>, 'finder_version': <django.forms.fields.IntegerField object>, 'firewall_enable': <django.forms.fields.BooleanField object>, 'firewall_version': <django.forms.fields.IntegerField object>, 'force_reset': <django.forms.fields.BooleanField object>, 'grace_period': <django.forms.fields.IntegerField object>, 'hidden_panes': <django.forms.fields.MultipleChoiceField object>, 'hide_admin': <django.forms.fields.BooleanField object>, 'history_limit': <django.forms.fields.ChoiceField object>, 'homepage': <django.forms.fields.CharField object>, 'host_info': <django.forms.fields.CharField object>, 'improve_siri': <django.forms.fields.ChoiceField object>, 'insecure_forms': <django.forms.fields.BooleanField object>, 'ipod_sync': <django.forms.fields.BooleanField object>, 'itunes_agreement': <django.forms.fields.BooleanField object>, 'itunes_file_share': <django.forms.fields.BooleanField object>, 'itunes_version': <django.forms.fields.IntegerField object>, 'java': <django.forms.fields.BooleanField object>, 'javascript': <django.forms.fields.BooleanField object>, 'library_sharing': <django.forms.fields.BooleanField object>, 'locked': <django.forms.fields.BooleanField object>, 'lockmessage_ui': <django.forms.fields.BooleanField object>, 'login_full_name': <django.forms.fields.BooleanField object>, 'login_version': <django.forms.fields.IntegerField object>, 'magnify': <django.forms.fields.BooleanField object>, 'magnify_immutable': <django.forms.fields.BooleanField object>, 'magsize_immutable': <django.forms.fields.BooleanField object>, 'mineffect': <django.forms.fields.ChoiceField object>, 'mineffect_immutable': <django.forms.fields.BooleanField object>, 'mini_app': <django.forms.fields.BooleanField object>, 'mobile_backups': <django.forms.fields.BooleanField object>, 'multiple_pages': <django.forms.fields.BooleanField object>, 'music_store': <django.forms.fields.BooleanField object>, 'new_tab': <django.forms.fields.ChoiceField object>, 'new_window': <django.forms.fields.ChoiceField object>, 'orientation': <django.forms.fields.ChoiceField object>, 'os_auto': <django.forms.fields.BooleanField object>, 'pass_autofill': <django.forms.fields.BooleanField object>, 'pass_proximity': <django.forms.fields.BooleanField object>, 'pass_share': <django.forms.fields.BooleanField object>, 'passcode_attempts': <django.forms.fields.IntegerField object>, 'passcode_force': <django.forms.fields.BooleanField object>, 'passcode_simple': <django.forms.fields.BooleanField object>, 'passcode_version': <django.forms.fields.IntegerField object>, 'password_change': <django.forms.fields.BooleanField object>, 'password_version': <django.forms.fields.IntegerField object>, 'pin_age': <django.forms.fields.IntegerField object>, 'pin_history': <django.forms.fields.IntegerField object>, 'pin_inactivity': <django.forms.fields.IntegerField object>, 'pin_min_length': <django.forms.fields.IntegerField object>, 'plugins': <django.forms.fields.BooleanField object>, 'policy_enable': <django.forms.fields.BooleanField object>, 'policy_version': <django.forms.fields.IntegerField object>, 'position': <django.forms.fields.BooleanField object>, 'power_loggedin': <django.forms.fields.BooleanField object>, 'preferences_version': <django.forms.fields.IntegerField object>, 'preferred_style': <django.forms.fields.ChoiceField object>, 'private_browsing': <django.forms.fields.BooleanField object>, 'process': <django.forms.fields.BooleanField object>, 'prohibit_connect': <django.forms.fields.BooleanField object>, 'prohibit_goto': <django.forms.fields.BooleanField object>, 'removal_date': <django.forms.fields.SplitDateTimeField object>, 'removal_period': <django.forms.fields.IntegerField object>, 'restart': <django.forms.fields.BooleanField object>, 'restart_loggedin': <django.forms.fields.BooleanField object>, 'restrictions_version': <django.forms.fields.IntegerField object>, 'retries_till_hint': <django.forms.fields.IntegerField object>, 'safari_version': <django.forms.fields.IntegerField object>, 'safe_downloads': <django.forms.fields.BooleanField object>, 'scope': <django.forms.fields.ChoiceField object>, 'screen_lock': <django.forms.fields.BooleanField object>, 'screensaver_delay': <django.forms.fields.IntegerField object>, 'screensaver_idle': <django.forms.fields.IntegerField object>, 'screensaver_password': <django.forms.fields.BooleanField object>, 'screensaver_path': <django.forms.fields.CharField object>, 'screensaver_version': <django.forms.fields.IntegerField object>, 'setup_version': <django.forms.fields.IntegerField object>, 'shared_music': <django.forms.fields.BooleanField object>, 'show_connected': <django.forms.fields.BooleanField object>, 'shutdown': <django.forms.fields.BooleanField object>, 'shutdown_loggedin': <django.forms.fields.BooleanField object>, 'siri_enabled': <django.forms.fields.BooleanField object>, 'siri_version': <django.forms.fields.IntegerField object>, 'size_immutable': <django.forms.fields.BooleanField object>, 'skip_appearance': <django.forms.fields.BooleanField object>, 'skip_cloud': <django.forms.fields.BooleanField object>, 'skip_cloud_storage': <django.forms.fields.BooleanField object>, 'skip_privacy': <django.forms.fields.BooleanField object>, 'skip_siri': <django.forms.fields.BooleanField object>, 'skip_true_tone': <django.forms.fields.BooleanField object>, 'sleep': <django.forms.fields.BooleanField object>, 'software_version': <django.forms.fields.IntegerField object>, 'softwareupdate_only': <django.forms.fields.BooleanField object>, 'spotlight_internet': <django.forms.fields.BooleanField object>, 'stealth': <django.forms.fields.BooleanField object>, 'store_version': <django.forms.fields.IntegerField object>, 'tab_links': <django.forms.fields.BooleanField object>, 'tab_policy': <django.forms.fields.ChoiceField object>, 'text': <django.forms.fields.CharField object>, 'time_machine_version': <django.forms.fields.IntegerField object>, 'time_reset': <django.forms.fields.IntegerField object>, 'update_check': <django.forms.fields.BooleanField object>, 'update_notifications': <django.forms.fields.BooleanField object>, 'version': <django.forms.fields.IntegerField object>, 'warn_trash': <django.forms.fields.BooleanField object>, 'window_target': <django.forms.fields.ChoiceField object>}
clean_desktop_version()[source]
clean_diagnostics_version()[source]
clean_dock_version()[source]
clean_energy_version()[source]
clean_filevault_version()[source]
clean_finder_version()[source]
clean_firewall_version()[source]
clean_itunes_version()[source]
clean_login_version()[source]
clean_passcode_version()[source]
clean_password_version()[source]
clean_policy_version()[source]
clean_preferences_version()[source]
clean_restrictions_version()[source]
clean_safari_version()[source]
clean_screensaver_version()[source]
clean_setup_version()[source]
clean_siri_version()[source]
clean_software_version()[source]
clean_store_version()[source]
clean_time_machine_version()[source]
clean_time_reset()[source]
declared_fields = {'ac_display_timer': <django.forms.fields.IntegerField object>, 'ac_power_failure': <django.forms.fields.BooleanField object>, 'ac_system_timer': <django.forms.fields.IntegerField object>, 'ac_wake_lan': <django.forms.fields.BooleanField object>, 'ac_wake_modem': <django.forms.fields.BooleanField object>, 'ad_tracking': <django.forms.fields.BooleanField object>, 'admin_install': <django.forms.fields.BooleanField object>, 'alpha': <django.forms.fields.BooleanField object>, 'anim': <django.forms.fields.BooleanField object>, 'anim_immutable': <django.forms.fields.BooleanField object>, 'app_adoption': <django.forms.fields.BooleanField object>, 'app_auto': <django.forms.fields.BooleanField object>, 'app_name_0': <django.forms.fields.CharField object>, 'app_path_0': <django.forms.fields.CharField object>, 'apple_music': <django.forms.fields.BooleanField object>, 'auto_backup': <django.forms.fields.BooleanField object>, 'auto_check': <django.forms.fields.BooleanField object>, 'auto_download': <django.forms.fields.BooleanField object>, 'auto_remove': <django.forms.fields.ChoiceField object>, 'autofill_address': <django.forms.fields.BooleanField object>, 'autofill_forms': <django.forms.fields.BooleanField object>, 'autohide': <django.forms.fields.BooleanField object>, 'autohide_immutable': <django.forms.fields.BooleanField object>, 'backup_size': <django.forms.fields.IntegerField object>, 'backup_sys': <django.forms.fields.BooleanField object>, 'backup_url': <django.forms.fields.CharField object>, 'backup_volumes': <django.forms.fields.BooleanField object>, 'battery_display_timer': <django.forms.fields.IntegerField object>, 'battery_power_failure': <django.forms.fields.BooleanField object>, 'battery_system_timer': <django.forms.fields.IntegerField object>, 'battery_wake_lan': <django.forms.fields.BooleanField object>, 'battery_wake_modem': <django.forms.fields.BooleanField object>, 'block_all': <django.forms.fields.BooleanField object>, 'caching': <django.forms.fields.BooleanField object>, 'cloud_address': <django.forms.fields.BooleanField object>, 'cloud_bookmarks': <django.forms.fields.BooleanField object>, 'cloud_cal': <django.forms.fields.BooleanField object>, 'cloud_doc_sync': <django.forms.fields.BooleanField object>, 'cloud_docs_desk': <django.forms.fields.BooleanField object>, 'cloud_keychain': <django.forms.fields.BooleanField object>, 'cloud_mail': <django.forms.fields.BooleanField object>, 'cloud_notes': <django.forms.fields.BooleanField object>, 'cloud_reminders': <django.forms.fields.BooleanField object>, 'command_click': <django.forms.fields.BooleanField object>, 'complexity': <django.forms.fields.IntegerField object>, 'config_install': <django.forms.fields.BooleanField object>, 'console': <django.forms.fields.BooleanField object>, 'content_immutable': <django.forms.fields.BooleanField object>, 'cookies': <django.forms.fields.ChoiceField object>, 'default_browser': <django.forms.fields.BooleanField object>, 'description': <django.forms.fields.CharField object>, 'desktop_path': <django.forms.fields.CharField object>, 'desktop_version': <django.forms.fields.IntegerField object>, 'developers_policy': <django.forms.fields.BooleanField object>, 'device_backups': <django.forms.fields.BooleanField object>, 'diagnostics': <django.forms.fields.BooleanField object>, 'diagnostics_version': <django.forms.fields.IntegerField object>, 'disable_airdrop': <django.forms.fields.BooleanField object>, 'disable_assistant': <django.forms.fields.BooleanField object>, 'disable_autounlock': <django.forms.fields.BooleanField object>, 'disable_beta': <django.forms.fields.BooleanField object>, 'disable_camera': <django.forms.fields.BooleanField object>, 'disable_context': <django.forms.fields.BooleanField object>, 'disable_handoff': <django.forms.fields.BooleanField object>, 'disable_password_change': <django.forms.fields.BooleanField object>, 'disable_screenshot': <django.forms.fields.BooleanField object>, 'disable_sleep': <django.forms.fields.BooleanField object>, 'disable_touchid': <django.forms.fields.BooleanField object>, 'disabled_panes': <django.forms.fields.MultipleChoiceField object>, 'disallow_notifications': <django.forms.fields.BooleanField object>, 'display_name': <django.forms.fields.CharField object>, 'dock_version': <django.forms.fields.IntegerField object>, 'downloads_clear': <django.forms.fields.ChoiceField object>, 'downloads_path': <django.forms.fields.CharField object>, 'ds_store': <django.forms.fields.BooleanField object>, 'empty_trash': <django.forms.fields.BooleanField object>, 'enable_protection': <django.forms.fields.BooleanField object>, 'enabled_panes': <django.forms.fields.MultipleChoiceField object>, 'energy_version': <django.forms.fields.IntegerField object>, 'extra_dock': <django.forms.fields.IntegerField object>, 'extra_firewall': <django.forms.fields.IntegerField object>, 'filename': <django.forms.fields.CharField object>, 'filevault': <django.forms.fields.BooleanField object>, 'filevault_version': <django.forms.fields.IntegerField object>, 'finder_version': <django.forms.fields.IntegerField object>, 'firewall_enable': <django.forms.fields.BooleanField object>, 'firewall_version': <django.forms.fields.IntegerField object>, 'force_reset': <django.forms.fields.BooleanField object>, 'grace_period': <django.forms.fields.IntegerField object>, 'hidden_panes': <django.forms.fields.MultipleChoiceField object>, 'hide_admin': <django.forms.fields.BooleanField object>, 'history_limit': <django.forms.fields.ChoiceField object>, 'homepage': <django.forms.fields.CharField object>, 'host_info': <django.forms.fields.CharField object>, 'improve_siri': <django.forms.fields.ChoiceField object>, 'insecure_forms': <django.forms.fields.BooleanField object>, 'ipod_sync': <django.forms.fields.BooleanField object>, 'itunes_agreement': <django.forms.fields.BooleanField object>, 'itunes_file_share': <django.forms.fields.BooleanField object>, 'itunes_version': <django.forms.fields.IntegerField object>, 'java': <django.forms.fields.BooleanField object>, 'javascript': <django.forms.fields.BooleanField object>, 'library_sharing': <django.forms.fields.BooleanField object>, 'locked': <django.forms.fields.BooleanField object>, 'lockmessage_ui': <django.forms.fields.BooleanField object>, 'login_full_name': <django.forms.fields.BooleanField object>, 'login_version': <django.forms.fields.IntegerField object>, 'magnify': <django.forms.fields.BooleanField object>, 'magnify_immutable': <django.forms.fields.BooleanField object>, 'magsize_immutable': <django.forms.fields.BooleanField object>, 'mineffect': <django.forms.fields.ChoiceField object>, 'mineffect_immutable': <django.forms.fields.BooleanField object>, 'mini_app': <django.forms.fields.BooleanField object>, 'mobile_backups': <django.forms.fields.BooleanField object>, 'multiple_pages': <django.forms.fields.BooleanField object>, 'music_store': <django.forms.fields.BooleanField object>, 'new_tab': <django.forms.fields.ChoiceField object>, 'new_window': <django.forms.fields.ChoiceField object>, 'orientation': <django.forms.fields.ChoiceField object>, 'os_auto': <django.forms.fields.BooleanField object>, 'pass_autofill': <django.forms.fields.BooleanField object>, 'pass_proximity': <django.forms.fields.BooleanField object>, 'pass_share': <django.forms.fields.BooleanField object>, 'passcode_attempts': <django.forms.fields.IntegerField object>, 'passcode_force': <django.forms.fields.BooleanField object>, 'passcode_simple': <django.forms.fields.BooleanField object>, 'passcode_version': <django.forms.fields.IntegerField object>, 'password_change': <django.forms.fields.BooleanField object>, 'password_version': <django.forms.fields.IntegerField object>, 'pin_age': <django.forms.fields.IntegerField object>, 'pin_history': <django.forms.fields.IntegerField object>, 'pin_inactivity': <django.forms.fields.IntegerField object>, 'pin_min_length': <django.forms.fields.IntegerField object>, 'plugins': <django.forms.fields.BooleanField object>, 'policy_enable': <django.forms.fields.BooleanField object>, 'policy_version': <django.forms.fields.IntegerField object>, 'position': <django.forms.fields.BooleanField object>, 'power_loggedin': <django.forms.fields.BooleanField object>, 'preferences_version': <django.forms.fields.IntegerField object>, 'preferred_style': <django.forms.fields.ChoiceField object>, 'private_browsing': <django.forms.fields.BooleanField object>, 'process': <django.forms.fields.BooleanField object>, 'prohibit_connect': <django.forms.fields.BooleanField object>, 'prohibit_goto': <django.forms.fields.BooleanField object>, 'removal_date': <django.forms.fields.SplitDateTimeField object>, 'removal_period': <django.forms.fields.IntegerField object>, 'restart': <django.forms.fields.BooleanField object>, 'restart_loggedin': <django.forms.fields.BooleanField object>, 'restrictions_version': <django.forms.fields.IntegerField object>, 'retries_till_hint': <django.forms.fields.IntegerField object>, 'safari_version': <django.forms.fields.IntegerField object>, 'safe_downloads': <django.forms.fields.BooleanField object>, 'scope': <django.forms.fields.ChoiceField object>, 'screen_lock': <django.forms.fields.BooleanField object>, 'screensaver_delay': <django.forms.fields.IntegerField object>, 'screensaver_idle': <django.forms.fields.IntegerField object>, 'screensaver_password': <django.forms.fields.BooleanField object>, 'screensaver_path': <django.forms.fields.CharField object>, 'screensaver_version': <django.forms.fields.IntegerField object>, 'setup_version': <django.forms.fields.IntegerField object>, 'shared_music': <django.forms.fields.BooleanField object>, 'show_connected': <django.forms.fields.BooleanField object>, 'shutdown': <django.forms.fields.BooleanField object>, 'shutdown_loggedin': <django.forms.fields.BooleanField object>, 'siri_enabled': <django.forms.fields.BooleanField object>, 'siri_version': <django.forms.fields.IntegerField object>, 'size_immutable': <django.forms.fields.BooleanField object>, 'skip_appearance': <django.forms.fields.BooleanField object>, 'skip_cloud': <django.forms.fields.BooleanField object>, 'skip_cloud_storage': <django.forms.fields.BooleanField object>, 'skip_privacy': <django.forms.fields.BooleanField object>, 'skip_siri': <django.forms.fields.BooleanField object>, 'skip_true_tone': <django.forms.fields.BooleanField object>, 'sleep': <django.forms.fields.BooleanField object>, 'software_version': <django.forms.fields.IntegerField object>, 'softwareupdate_only': <django.forms.fields.BooleanField object>, 'spotlight_internet': <django.forms.fields.BooleanField object>, 'stealth': <django.forms.fields.BooleanField object>, 'store_version': <django.forms.fields.IntegerField object>, 'tab_links': <django.forms.fields.BooleanField object>, 'tab_policy': <django.forms.fields.ChoiceField object>, 'text': <django.forms.fields.CharField object>, 'time_machine_version': <django.forms.fields.IntegerField object>, 'time_reset': <django.forms.fields.IntegerField object>, 'update_check': <django.forms.fields.BooleanField object>, 'update_notifications': <django.forms.fields.BooleanField object>, 'version': <django.forms.fields.IntegerField object>, 'warn_trash': <django.forms.fields.BooleanField object>, 'window_target': <django.forms.fields.ChoiceField object>}
fields = {}
media
class devices.forms.ProfileRemovalForm(*args, **kwargs)[source]
base_fields = {'options': <django.forms.fields.ChoiceField object>}
declared_fields = {'options': <django.forms.fields.ChoiceField object>}
media
class devices.forms.RemovalForm(*args, **kwargs)[source]
base_fields = {'agree': <django.forms.fields.BooleanField object>, 'client_removed': <django.forms.fields.BooleanField object>, 'profiles_removed': <django.forms.fields.BooleanField object>}
declared_fields = {'agree': <django.forms.fields.BooleanField object>, 'client_removed': <django.forms.fields.BooleanField object>, 'profiles_removed': <django.forms.fields.BooleanField object>}
media
class devices.forms.UninstallAppForm(*args, **kwargs)[source]
base_fields = {}
declared_fields = {}
media
class devices.forms.UpdateAppForm(*args, **kwargs)[source]
class Meta[source]
fields = ['name', 'identifier', 'developer', 'version', 'description', 'developer_website', 'requires_license']
model

alias of devices.models.MacOSApp

base_fields = {'description': <django.forms.fields.CharField object>, 'developer': <django.forms.fields.CharField object>, 'developer_website': <django.forms.fields.URLField object>, 'identifier': <django.forms.fields.CharField object>, 'name': <django.forms.fields.CharField object>, 'requires_license': <django.forms.fields.BooleanField object>, 'version': <django.forms.fields.CharField object>}
declared_fields = {}
media

Emails

This module is used to manage LNL’s email communications.

Models

class emails.models.MeetingNoticeMail(*args, **kwargs)[source]

Meeting Notice Email

Parameters:
  • id (AutoField) – Id (required)
  • ts (DateTimeField) – Ts (required)
  • place (CharField) – Place (default=AK219)
  • time (TimeField) – Time (default=17:00)
  • date (DateField) – Date (required)
  • note (TextField) – Note (required)
  • start_param (DateField) – Start param (required)
  • end_param (DateField) – End param (required)
  • sent (BooleanField) – Sent (default=False)
exception DoesNotExist
exception MultipleObjectsReturned
date

DateField()

end_param

DateField()

get_next_by_date(*, field=<django.db.models.fields.DateField: date>, is_next=True, **kwargs)
get_next_by_end_param(*, field=<django.db.models.fields.DateField: end_param>, is_next=True, **kwargs)
get_next_by_start_param(*, field=<django.db.models.fields.DateField: start_param>, is_next=True, **kwargs)
get_next_by_ts(*, field=<django.db.models.fields.DateTimeField: ts>, is_next=True, **kwargs)
get_previous_by_date(*, field=<django.db.models.fields.DateField: date>, is_next=False, **kwargs)
get_previous_by_end_param(*, field=<django.db.models.fields.DateField: end_param>, is_next=False, **kwargs)
get_previous_by_start_param(*, field=<django.db.models.fields.DateField: start_param>, is_next=False, **kwargs)
get_previous_by_ts(*, field=<django.db.models.fields.DateTimeField: ts>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

note

TextField()

objects = <django.db.models.manager.Manager object>
place

CharField(max_length=32, default=”AK219”)

sent

BooleanField(default=False)

start_param

DateField()

time

TimeField(default=”17:00”)

ts

DateTimeField(auto_now_add=True)

class emails.models.SMSMessage(*args, **kwargs)[source]

SMS Text Message

Parameters:
  • id (AutoField) – Id (required)
  • user (ForeignKey to User) – User (required)
  • message (TextField) – Message (required)
exception DoesNotExist
exception MultipleObjectsReturned
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

message

TextField()

objects = <django.db.models.manager.Manager object>
user

ForeignKey(on_delete=CASCADE(), to= User)

user_id

Raw (integer) FK for user


Views

class emails.views.MeetingAnnounceCCView(**kwargs)[source]
model

alias of meetings.models.CCNoticeSend

slug_field = 'uuid'
template_name = 'emails/email_notice_cc.html'
class emails.views.MeetingAnnounceView(**kwargs)[source]
model

alias of meetings.models.MeetingAnnounce

slug_field = 'uuid'
template_name = 'emails/email_notice.html'
emails.views.dispatch_console(request)[source]

Menu for email tools

emails.views.mk_srv_announce(request)[source]

Send out a web service announcement

emails.views.poke_cc(request)[source]

Send a “Poke for CC” email (searching for crew chiefs)

emails.views.send_active_sms(request)[source]

Send a text message to all active members (must have opted-in to receive text messages)

emails.views.send_sms(request)[source]

Send a text message to a specific user (must have opted-in to receive messages)


Generators

class emails.generators.BasicEmailGenerator(to_emails='lnl@wpi.edu', from_email='WPI Lens and Lights <lnl-no-reply@wpi.edu>', reply_to=None, bcc=None, context=None, template_basename='emails/email_basic', body=None)[source]

Non-HTML email with no LNL branding or formatting. Uses no-reply address by default.

send()[source]
class emails.generators.BillingEmailGenerator(event=None, subject='Invoice for LNL Services', to_emails='lnl@wpi.edu', cc=None, bcc=['lnl-t@wpi.edu'], from_email='WPI Lens and Lights <lnl@wpi.edu>', reply_to=['lnl-t@wpi.edu'], context=None, template_basename='emails/email_billing', build_html=True, body=None, attachments=None)[source]
class emails.generators.CcAddEmailGenerator(ccinstance=None, subject='Crew Chief Add Notification', to_emails=None, cc=None, bcc=None, from_email='WPI Lens and Lights <lnl@wpi.edu>', reply_to=None, context=None, template_basename='emails/email_ccadd', build_html=True, attachments=None)[source]
class emails.generators.DefaultLNLEmailGenerator(subject='LNL Notice', to_emails='lnl@wpi.edu', cc=None, bcc=None, from_email='WPI Lens and Lights <lnl@wpi.edu>', reply_to=None, context=None, template_basename='emails/email_generic', build_html=True, body=None, attachments=None)[source]
send()[source]
class emails.generators.EventEmailGenerator(event=None, subject='LNL Event', to_emails='lnl@wpi.edu', cc=None, bcc=None, from_email='WPI Lens and Lights <lnl@wpi.edu>', reply_to=None, context=None, template_basename='emails/email_event', build_html=True, body=None, attachments=None)[source]
class emails.generators.GenericEmailGenerator(subject=None, to_emails='lnl@wpi.edu', cc=None, bcc=None, from_email='WPI Lens and Lights <lnl@wpi.edu>', reply_to=None, context=None, build_html=True, body=None, attachments=None)[source]
class emails.generators.ReportReminderEmailGenerator(reminder=None, subject='LNL Crew Chief Report Reminder Email', to_emails=None, cc=None, bcc=None, from_email='WPI Lens and Lights <lnl@wpi.edu>', reply_to=None, context=None, template_basename='emails/email_reportreminder', build_html=True, attachments=None)[source]
class emails.generators.SurveyEmailGenerator(event=None, subject='Post-event survey for your recent event', to_emails='lnl@wpi.edu', cc=None, bcc=['gr-lnl-vp-db@wpi.edu'], from_email='WPI Lens and Lights <lnl@wpi.edu>', reply_to=None, context=None, template_basename='emails/email_survey', build_html=True, attachments=None)[source]
emails.generators.generate_event_start_end_emails()[source]

Send an email for events starting or ending now

emails.generators.generate_notice_cc_email(notice)[source]

Generate a meeting notice email

Parameters:notice – A MeetingNoticeMail object
Returns:An email object
emails.generators.generate_notice_email(notice)[source]

Generate a meeting notice email

Parameters:notice – A MeetingNoticeMail object
Returns:An email object
emails.generators.generate_poke_cc_email_content(services, message)[source]

Generate the body of a “Poke for CC” email notification

Parameters:
  • services – An array or queryset of services crew chiefs are needed for
  • message – Additional message to display above the event details (Optional, but highly recommended)
Returns:

HTML formatted string

emails.generators.generate_selfservice_notice_email(context)[source]

Generate an email notification when a new client submits a self-service request

Parameters:context – Self-service form data
Returns:An email object
emails.generators.generate_sms_email(data)[source]

Generate a plain SMS text message for delivery via email

Parameters:data – A dictionary - {‘message’: <str>, ‘user’: <User>}
Returns:A basic (non-HTML) email object
emails.generators.generate_transfer_email(orgtransfer)[source]

Generate an organization transfer email notification

Parameters:orgtransfer – An OrganizationTransfer object
Returns:An email object
emails.generators.generate_web_service_email(details)[source]

Generate a generic email message with the Webmaster listed as the reply address

Parameters:details – A dictionary - {‘subject’: <str>, ‘message’: <str>, ‘email_to’: <str>}
Returns:A generic LNL email object
emails.generators.send_survey_if_necessary(event)[source]

Check to see if a post-event survey should be sent for a particular event. If so, send an email to the client.

Parameters:event – The event

Events

This is perhaps the largest module in the LNLDB project and is central to a lot of what the LNLDB does. It manages details about LNL’s services and event bookings.

Models

class events.models.BaseEvent(*args, **kwargs)[source]

This parent class is inherited by both Event and Event2019. It contains the parts of the old Event model that were kept in Event2019. The parts of the old Event model that were _not_ kept in Event2019 remain in the Event model.

Parameters:
  • id (AutoField) – Id (required)
  • polymorphic_ctype (ForeignKey to ContentType) – Polymorphic ctype
  • submitted_by (ForeignKey to User) – Submitted by (required)
  • submitted_ip (GenericIPAddressField) – Submitted ip (required)
  • submitted_on (DateTimeField) – Submitted on (required)
  • event_name (CharField) – Event name (required)
  • description (TextField) – Description
  • location (ForeignKey to Location) – Location (required)
  • contact (ForeignKey to User) – Contact
  • lnl_contact (ForeignKey to User) – Lnl contact
  • billing_org (ForeignKey to Organization) – Billing org
  • datetime_setup_complete (DateTimeField) – Datetime setup complete (required)
  • datetime_start (DateTimeField) – Datetime start (required)
  • datetime_end (DateTimeField) – Datetime end (required)
  • internal_notes (TextField) – Notes that the client and general body should never see.
  • billed_in_bulk (BooleanField) – Check if billing of this event will be deferred so that it can be combined with other events in a single invoice (default=False)
  • sensitive (BooleanField) – Nobody besides those directly involved should know about this event (default=False)
  • test_event (BooleanField) – Check to lower the VP’s blood pressure after they see the short-notice S4/L4 (default=False)
  • approved (BooleanField) – Approved (default=False)
  • approved_on (DateTimeField) – Approved on
  • approved_by (ForeignKey to User) – Approved by
  • reviewed (BooleanField) – Reviewed (default=False)
  • reviewed_on (DateTimeField) – Reviewed on
  • reviewed_by (ForeignKey to User) – Reviewed by
  • closed (BooleanField) – Closed (default=False)
  • closed_on (DateTimeField) – Closed on
  • closed_by (ForeignKey to User) – Closed by
  • cancelled (BooleanField) – Cancelled (default=False)
  • cancelled_on (DateTimeField) – Cancelled on
  • cancelled_by (ForeignKey to User) – Cancelled by
  • cancelled_reason (TextField) – Cancelled reason
  • org (ManyToManyField to Organization) – Client (required)
exception DoesNotExist
exception MultipleObjectsReturned
approved

BooleanField(default=False)

approved_by

ForeignKey(blank=True, null=True, related_name=”eventapprovals”, on_delete=PROTECT(), to= User)

approved_by_id

Raw (integer) FK for approved_by

approved_on

DateTimeField(blank=True, null=True)

arbitraryfees

Reverse Manager for events.EventArbitrary’s event

attachments

Reverse Manager for events.EventAttachment’s event

billed_in_bulk

BooleanField(db_index=True, default=False, help_text=”Check if billing of this event will be deferred so that it can be combined with other events in a single invoice”)

Billed in bulk: Check if billing of this event will be deferred so that it can be combined with other events in a single invoice

billing_org

ForeignKey(blank=True, null=True, related_name=”billedevents”, on_delete=PROTECT(), to= Organization)

billing_org_id

Raw (integer) FK for billing_org

billings

Reverse Manager for events.Billing’s event

cal_desc()[source]

Event description used by calendars

cal_end()[source]

End time used by calendars

cal_guid()[source]

Unique event id for use by calendars

Link to display on calendars

cal_location()[source]

Location data to display on calendars

cal_name()[source]

Title to display on calendars

cal_start()[source]

Start time used by calendars

cancelled

BooleanField(default=False)

cancelled_by

ForeignKey(blank=True, null=True, related_name=”eventcancellations”, on_delete=PROTECT(), to= User)

cancelled_by_id

Raw (integer) FK for cancelled_by

cancelled_on

DateTimeField(blank=True, null=True)

cancelled_reason

TextField(blank=True, null=True)

ccinstances

Reverse Manager for events.EventCCInstance’s event

ccreport_set

Reverse Manager for events.CCReport’s event

ccreportreminders

Reverse Manager for events.ReportReminder’s event

closed

BooleanField(default=False)

closed_by

ForeignKey(blank=True, null=True, related_name=”eventclosings”, on_delete=PROTECT(), to= User)

closed_by_id

Raw (integer) FK for closed_by

closed_on

DateTimeField(blank=True, null=True)

contact

ForeignKey(verbose_name=”Contact”, blank=True, null=True, related_name=”contact”, on_delete=PROTECT(), to= User)

contact_id

Raw (integer) FK for contact

crew_needing_reports

List of crew chiefs who have not yet submitted a CC report

datetime_end

DateTimeField()

datetime_nice
datetime_setup_complete

DateTimeField()

datetime_start

DateTimeField(db_index=True)

description

TextField(blank=True, null=True)

event

Accessor to the related object on the reverse side of a one-to-one relation.

In the example:

class Restaurant(Model):
    place = OneToOneField(Place, related_name='restaurant')

Place.restaurant is a ReverseOneToOneDescriptor instance.

event2019

Accessor to the related object on the reverse side of a one-to-one relation.

In the example:

class Restaurant(Model):
    place = OneToOneField(Place, related_name='restaurant')

Place.restaurant is a ReverseOneToOneDescriptor instance.

event_name

CharField(max_length=128, db_index=True)

eventcount
eventservices
extrainstance_set

Reverse Manager for events.ExtraInstance’s event

get_next_by_datetime_end(*, field=<django.db.models.fields.DateTimeField: datetime_end>, is_next=True, **kwargs)
get_next_by_datetime_setup_complete(*, field=<django.db.models.fields.DateTimeField: datetime_setup_complete>, is_next=True, **kwargs)
get_next_by_datetime_start(*, field=<django.db.models.fields.DateTimeField: datetime_start>, is_next=True, **kwargs)
get_next_by_submitted_on(*, field=<django.db.models.fields.DateTimeField: submitted_on>, is_next=True, **kwargs)
get_previous_by_datetime_end(*, field=<django.db.models.fields.DateTimeField: datetime_end>, is_next=False, **kwargs)
get_previous_by_datetime_setup_complete(*, field=<django.db.models.fields.DateTimeField: datetime_setup_complete>, is_next=False, **kwargs)
get_previous_by_datetime_start(*, field=<django.db.models.fields.DateTimeField: datetime_start>, is_next=False, **kwargs)
get_previous_by_submitted_on(*, field=<django.db.models.fields.DateTimeField: submitted_on>, is_next=False, **kwargs)
has_projection
hours

Reverse Manager for events.Hours’s event

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

internal_notes

TextField(blank=True, null=True, help_text=”Notes that the client and general body should never see.”)

Internal notes: Notes that the client and general body should never see.

last_bill
last_billed
last_paid
late
lnl_contact

ForeignKey(verbose_name=”LNL Contact”, blank=True, null=True, related_name=”lnl_contact”, on_delete=PROTECT(), to= User)

lnl_contact_id

Raw (integer) FK for lnl_contact

location

ForeignKey(on_delete=PROTECT(), to= Location)

location_id

Raw (integer) FK for location

meetingannouncements

Reverse Manager for meetings.MeetingAnnounce’s events

meetingccnoticeevents

Reverse Manager for meetings.CCNoticeSend’s events

multibillings

Reverse Manager for events.MultiBilling’s events

num_crew_needing_reports
oneoff_total
oneoffs
org

Reverse Manager for events.BaseEvent’s org

org_to_be_billed
over
paid
polymorphic_ctype

ForeignKey(null=True, editable=False, related_name=”polymorphic_events.baseevent_set+”, on_delete=CASCADE(), to= ContentType)

polymorphic_primary_key_name = 'id'
polymorphic_super_sub_accessors_replaced = False
reports_editable

Returns false if too much time has elapsed since the end of the event

reviewed

BooleanField(default=False)

reviewed_by

ForeignKey(blank=True, null=True, related_name=”eventbillingreview”, on_delete=PROTECT(), to= User)

reviewed_by_id

Raw (integer) FK for reviewed_by

reviewed_on

DateTimeField(blank=True, null=True)

sensitive

BooleanField(default=False, help_text=”Nobody besides those directly involved should know about this event”)

Sensitive: Nobody besides those directly involved should know about this event

serviceinstance_set

Reverse Manager for events.ServiceInstance’s event

short_services
status
submitted_by

ForeignKey(related_name=”submitter”, on_delete=PROTECT(), to= User)

submitted_by_id

Raw (integer) FK for submitted_by

submitted_ip

GenericIPAddressField()

submitted_on

DateTimeField(db_index=True, auto_now_add=True)

surveys

Reverse Manager for events.PostEventSurvey’s event

test_event

BooleanField(default=False, help_text=”Check to lower the VP’s blood pressure after they see the short-notice S4/L4”)

Test event: Check to lower the VP’s blood pressure after they see the short-notice S4/L4

times_billed
unpaid
class events.models.Billing(*args, **kwargs)[source]

A billing instance that is sent to a client

Parameters:
  • id (AutoField) – Id (required)
  • date_billed (DateField) – Date billed (required)
  • date_paid (DateField) – Date paid
  • event (ForeignKey to BaseEvent) – Event (required)
  • amount (DecimalField) – Amount (required)
exception DoesNotExist
exception MultipleObjectsReturned
amount

DecimalField(max_digits=8, decimal_places=2)

billingemail_set

Reverse Manager for events.BillingEmail’s billing

date_billed

DateField()

date_paid

DateField(blank=True, null=True)

event

ForeignKey(related_name=”billings”, on_delete=CASCADE(), to= BaseEvent)

event_id

Raw (integer) FK for event

get_next_by_date_billed(*, field=<django.db.models.fields.DateField: date_billed>, is_next=True, **kwargs)
get_previous_by_date_billed(*, field=<django.db.models.fields.DateField: date_billed>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
class events.models.BillingEmail(*args, **kwargs)[source]

Billing information used in an email sent to a client

Parameters:
  • id (AutoField) – Id (required)
  • billing (ForeignKey to Billing) – Billing (required)
  • subject (CharField) – Subject (required)
  • message (TextField) – Message (required)
  • sent_at (DateTimeField) – Sent at
  • email_to_users (ManyToManyField to User) – Email to users (required)
  • email_to_orgs (ManyToManyField to Organization) – Email to orgs (required)
exception DoesNotExist
exception MultipleObjectsReturned
billing

ForeignKey(on_delete=CASCADE(), to= Billing)

billing_id

Raw (integer) FK for billing

email_to_orgs

Reverse Manager for events.BillingEmail’s email_to_orgs

email_to_users

Reverse Manager for events.BillingEmail’s email_to_users

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

message

TextField()

objects = <django.db.models.manager.Manager object>
sent_at

DateTimeField(null=True)

subject

CharField(max_length=128)

class events.models.Building(*args, **kwargs)[source]

Used to group locations together in forms

Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – Name (required)
  • shortname (CharField) – Shortname (required)
exception DoesNotExist
exception MultipleObjectsReturned
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

location_set

Reverse Manager for events.Location’s building

name

CharField(max_length=128)

objects = <django.db.models.manager.Manager object>
shortname

CharField(max_length=4)

class events.models.CCReport(*args, **kwargs)[source]

Crew Chief post-event report

Parameters:
  • id (AutoField) – Id (required)
  • crew_chief (ForeignKey to User) – Crew chief (required)
  • event (ForeignKey to BaseEvent) – Event (required)
  • report (TextField) – Report (required)
  • created_on (DateTimeField) – Created on (required)
  • updated_on (DateTimeField) – Updated on (required)
  • for_service_cat (ManyToManyField to Category) – Services (required)
exception DoesNotExist
exception MultipleObjectsReturned
created_on

DateTimeField(auto_now_add=True)

crew_chief

ForeignKey(on_delete=PROTECT(), to= User)

crew_chief_id

Raw (integer) FK for crew_chief

event

ForeignKey(on_delete=CASCADE(), to= BaseEvent)

event_id

Raw (integer) FK for event

for_service_cat

Reverse Manager for events.CCReport’s for_service_cat

get_next_by_created_on(*, field=<django.db.models.fields.DateTimeField: created_on>, is_next=True, **kwargs)
get_next_by_updated_on(*, field=<django.db.models.fields.DateTimeField: updated_on>, is_next=True, **kwargs)
get_previous_by_created_on(*, field=<django.db.models.fields.DateTimeField: created_on>, is_next=False, **kwargs)
get_previous_by_updated_on(*, field=<django.db.models.fields.DateTimeField: updated_on>, is_next=False, **kwargs)
glyphicon = 'comment'
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
pretty_cat_list

Generates a nice list of the respective service categories

report

TextField(validators=[<django.core.validators.MinLengthValidator object at 0x7f60a2b6fc90>])

updated_on

DateTimeField(auto_now=True)

class events.models.Category(*args, **kwargs)[source]

A category

Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – Name (required)
exception DoesNotExist
exception MultipleObjectsReturned
ccinstances

Reverse Manager for events.EventCCInstance’s category

ccreport_set

Reverse Manager for events.CCReport’s for_service_cat

extra_set

Reverse Manager for events.Extra’s category

hours

Reverse Manager for events.Hours’s category

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

name

CharField(max_length=16)

objects = <django.db.models.manager.Manager object>
service_set

Reverse Manager for events.Service’s category

class events.models.CrewAttendanceRecord(*args, **kwargs)[source]

Checkin and checkout times for a crew member attending an event

Parameters:
  • id (AutoField) – Id (required)
  • user (ForeignKey to User) – User (required)
  • event (ForeignKey to Event2019) – Event
  • checkin (DateTimeField) – Checkin (default=<function now at 0x7f60a49248c0>)
  • checkout (DateTimeField) – Checkout
  • active (BooleanField) – Active (default=True)
exception DoesNotExist
exception MultipleObjectsReturned
active

BooleanField(default=True)

checkin

DateTimeField(default=now())

checkout

DateTimeField(blank=True, null=True)

event

ForeignKey(null=True, related_name=”crew_attendance”, on_delete=SET_NULL(), to= Event2019)

event_id

Raw (integer) FK for event

get_next_by_checkin(*, field=<django.db.models.fields.DateTimeField: checkin>, is_next=True, **kwargs)
get_previous_by_checkin(*, field=<django.db.models.fields.DateTimeField: checkin>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
user

ForeignKey(related_name=”event_records”, on_delete=CASCADE(), to= User)

user_id

Raw (integer) FK for user

class events.models.Event(*args, **kwargs)[source]

An Event, What everything ends up pointing to

This model is full of old garbage that was not kept in Event2019. Let it rest in peace.

Parameters:
  • id (AutoField) – Id (required)
  • polymorphic_ctype (ForeignKey to ContentType) – Polymorphic ctype
  • submitted_by (ForeignKey to User) – Submitted by (required)
  • submitted_ip (GenericIPAddressField) – Submitted ip (required)
  • submitted_on (DateTimeField) – Submitted on (required)
  • event_name (CharField) – Event name (required)
  • description (TextField) – Description
  • location (ForeignKey to Location) – Location (required)
  • contact (ForeignKey to User) – Contact
  • lnl_contact (ForeignKey to User) – Lnl contact
  • billing_org (ForeignKey to Organization) – Billing org
  • datetime_setup_complete (DateTimeField) – Datetime setup complete (required)
  • datetime_start (DateTimeField) – Datetime start (required)
  • datetime_end (DateTimeField) – Datetime end (required)
  • internal_notes (TextField) – Notes that the client and general body should never see.
  • billed_in_bulk (BooleanField) – Check if billing of this event will be deferred so that it can be combined with other events in a single invoice (default=False)
  • sensitive (BooleanField) – Nobody besides those directly involved should know about this event (default=False)
  • test_event (BooleanField) – Check to lower the VP’s blood pressure after they see the short-notice S4/L4 (default=False)
  • approved (BooleanField) – Approved (default=False)
  • approved_on (DateTimeField) – Approved on
  • approved_by (ForeignKey to User) – Approved by
  • reviewed (BooleanField) – Reviewed (default=False)
  • reviewed_on (DateTimeField) – Reviewed on
  • reviewed_by (ForeignKey to User) – Reviewed by
  • closed (BooleanField) – Closed (default=False)
  • closed_on (DateTimeField) – Closed on
  • closed_by (ForeignKey to User) – Closed by
  • cancelled (BooleanField) – Cancelled (default=False)
  • cancelled_on (DateTimeField) – Cancelled on
  • cancelled_by (ForeignKey to User) – Cancelled by
  • cancelled_reason (TextField) – Cancelled reason
  • org (ManyToManyField to Organization) – Client (required)
  • baseevent_ptr (OneToOneField to BaseEvent) – Baseevent ptr (required)
  • datetime_setup_start (DateTimeField) – Datetime setup start
  • lighting (ForeignKey to Lighting) – Lighting
  • sound (ForeignKey to Sound) – Sound
  • projection (ForeignKey to Projection) – Projection
  • lighting_reqs (TextField) – Lighting reqs
  • sound_reqs (TextField) – Sound reqs
  • proj_reqs (TextField) – Proj reqs
  • otherservice_reqs (TextField) – Otherservice reqs
  • setup_location (ForeignKey to Location) – Setup location
  • payment_amount (IntegerField) – Payment amount (default=None)
  • ccs_needed (PositiveIntegerField) – Ccs needed (default=0)
  • otherservices (ManyToManyField to Service) – Otherservices (required)
  • crew_chief (ManyToManyField to User) – Crew chief (required)
  • crew (ManyToManyField to User) – Crew (required)
exception DoesNotExist
exception MultipleObjectsReturned
allservices
attachment_for_lighting
attachment_for_projection
attachment_for_sound
baseevent_ptr

OneToOneField(primary_key=True, serialize=False, auto_created=True, on_delete=CASCADE(), parent_link=True, to= BaseEvent)

baseevent_ptr_id

Raw (integer) FK for baseevent_ptr

ccreport_url()[source]
ccs_needed

PositiveIntegerField(db_index=True, default=0)

contact_addr
contact_email
contact_name
contact_phone
cost_lighting_extras
cost_lighting_total
cost_other_extras
cost_other_services
cost_projection_extras
cost_projection_total
cost_sound_extras
cost_sound_total
cost_total
cost_total_pre_discount
crew

Reverse Manager for events.Event’s crew

crew_chief

Reverse Manager for events.Event’s crew_chief

datetime_setup_start

DateTimeField(blank=True, null=True, db_index=True)

discount_applied
discount_value
event_mg = <events.models.EventManager object>
eventcount
eventservices
extras_lighting
extras_other
extras_projection
extras_sound
extras_total
firstorg()[source]
glyphicon = 'bullhorn'
has_projection
lighting

ForeignKey(blank=True, null=True, related_name=”lighting”, on_delete=PROTECT(), to= Lighting)

lighting_id

Raw (integer) FK for lighting

lighting_reqs

TextField(blank=True, null=True)

objects = <events.models.OptimizedEventManager object>
otherservice_reqs

TextField(blank=True, null=True)

otherservices

Reverse Manager for events.Event’s otherservices

payment_amount

IntegerField(blank=True, null=True, default=None)

person_name
polymorphic_primary_key_name = 'id'
polymorphic_super_sub_accessors_replaced = False
pretty_title
proj_reqs

TextField(blank=True, null=True)

projection

ForeignKey(blank=True, null=True, related_name=”projection”, on_delete=PROTECT(), to= Projection)

projection_id

Raw (integer) FK for projection

return_orgs_and_associates()[source]
save(force_insert=False, force_update=False, using=None, update_fields=None)[source]

Calls pre_save_polymorphic() and saves the model.

services_other
setup_location

ForeignKey(blank=True, null=True, related_name=”setuplocation”, on_delete=PROTECT(), to= Location)

setup_location_id

Raw (integer) FK for setup_location

short_services
sound

ForeignKey(blank=True, null=True, related_name=”sound”, on_delete=PROTECT(), to= Sound)

sound_id

Raw (integer) FK for sound

sound_reqs

TextField(blank=True, null=True)

usercanseeevent(user)[source]
class events.models.Event2019(*args, **kwargs)[source]

New events under the 2019 pricelist

Parameters:
  • id (AutoField) – Id (required)
  • polymorphic_ctype (ForeignKey to ContentType) – Polymorphic ctype
  • submitted_by (ForeignKey to User) – Submitted by (required)
  • submitted_ip (GenericIPAddressField) – Submitted ip (required)
  • submitted_on (DateTimeField) – Submitted on (required)
  • event_name (CharField) – Event name (required)
  • description (TextField) – Description
  • location (ForeignKey to Location) – Location (required)
  • contact (ForeignKey to User) – Contact
  • lnl_contact (ForeignKey to User) – Lnl contact
  • billing_org (ForeignKey to Organization) – Billing org
  • datetime_setup_complete (DateTimeField) – Datetime setup complete (required)
  • datetime_start (DateTimeField) – Datetime start (required)
  • datetime_end (DateTimeField) – Datetime end (required)
  • internal_notes (TextField) – Notes that the client and general body should never see.
  • billed_in_bulk (BooleanField) – Check if billing of this event will be deferred so that it can be combined with other events in a single invoice (default=False)
  • sensitive (BooleanField) – Nobody besides those directly involved should know about this event (default=False)
  • test_event (BooleanField) – Check to lower the VP’s blood pressure after they see the short-notice S4/L4 (default=False)
  • approved (BooleanField) – Approved (default=False)
  • approved_on (DateTimeField) – Approved on
  • approved_by (ForeignKey to User) – Approved by
  • reviewed (BooleanField) – Reviewed (default=False)
  • reviewed_on (DateTimeField) – Reviewed on
  • reviewed_by (ForeignKey to User) – Reviewed by
  • closed (BooleanField) – Closed (default=False)
  • closed_on (DateTimeField) – Closed on
  • closed_by (ForeignKey to User) – Closed by
  • cancelled (BooleanField) – Cancelled (default=False)
  • cancelled_on (DateTimeField) – Cancelled on
  • cancelled_by (ForeignKey to User) – Cancelled by
  • cancelled_reason (TextField) – Cancelled reason
  • org (ManyToManyField to Organization) – Client (required)
  • baseevent_ptr (OneToOneField to BaseEvent) – Baseevent ptr (required)
  • workday_fund (IntegerField) – Workday fund
  • worktag (CharField) – Worktag
  • workday_form_comments (TextField) – Workday form comments
  • workday_entered_by (ForeignKey to User) – Workday entered by
  • entered_into_workday (BooleanField) – Checked when the Treasurer has created an Internal Service Delivery in Workday for this event (default=False)
  • send_survey (BooleanField) – Check if the event contact should be emailed the post-event survey after the event (default=True)
  • survey_sent (BooleanField) – The post-event survey has been sent to the client (default=False)
  • max_crew (PositiveIntegerField) – Max crew
  • reference_code (CharField) – The 25Live reference code, found on the event page
  • event_id (IntegerField) – The 25Live event ID. If not provided, it will be generated from the reference code.
exception DoesNotExist
exception MultipleObjectsReturned
allservices
baseevent_ptr

OneToOneField(primary_key=True, serialize=False, auto_created=True, on_delete=CASCADE(), parent_link=True, to= BaseEvent)

baseevent_ptr_id

Raw (integer) FK for baseevent_ptr

cost_total
cost_total_pre_discount
crew_attendance

Reverse Manager for events.CrewAttendanceRecord’s event

discount_applied
discount_value
entered_into_workday

BooleanField(default=False, help_text=”Checked when the Treasurer has created an Internal Service Delivery in Workday for this event”)

Entered into workday: Checked when the Treasurer has created an Internal Service Delivery in Workday for this event

event_id

IntegerField(blank=True, null=True, help_text=”The 25Live event ID. If not provided, it will be generated from the reference code.”)

Event id: The 25Live event ID. If not provided, it will be generated from the reference code.

eventcount

Number of different types of services provided (based on category)

eventservices
extras_total
get_workday_fund_display(*, field=<django.db.models.fields.IntegerField: workday_fund>)
has_projection
max_crew

PositiveIntegerField(blank=True, null=True)

polymorphic_primary_key_name = 'id'
polymorphic_super_sub_accessors_replaced = False
reference_code

CharField(max_length=12, blank=True, null=True, help_text=”The 25Live reference code, found on the event page”)

Reference code: The 25Live reference code, found on the event page

send_survey

BooleanField(default=True, help_text=”Check if the event contact should be emailed the post-event survey after the event”)

Send survey: Check if the event contact should be emailed the post-event survey after the event

services_total
session_set

Reverse Manager for spotify.Session’s event

short_services
survey_sent

BooleanField(default=False, help_text=”The post-event survey has been sent to the client”)

Survey sent: The post-event survey has been sent to the client

workday_entered_by

ForeignKey(blank=True, null=True, related_name=”workdayentries”, on_delete=PROTECT(), to= User)

workday_entered_by_id

Raw (integer) FK for workday_entered_by

workday_form_comments

TextField(blank=True, null=True)

workday_form_hash
workday_fund

IntegerField(blank=True, null=True, choices=[(810, ‘Student Organization (810-FD)’), (110, ‘Operating (110-FD)’), (220, ‘Gift (220-FD)’), (250, ‘Gift (250-FD)’), (500, ‘Gift (500-FD)’), (210, ‘Grant (210-FD)’), (900, ‘Project (900-FD)’), (120, ‘Designated (120-FD)’)])

worktag

CharField(max_length=10, blank=True, null=True)

class events.models.EventArbitrary(*args, **kwargs)[source]

Additional “OneOff” charges (i.e. rentals, additional fees)

Parameters:
  • id (AutoField) – Id (required)
  • event (ForeignKey to BaseEvent) – Event (required)
  • key_name (CharField) – Key name (required)
  • key_value (DecimalField) – Key value (required)
  • key_quantity (PositiveSmallIntegerField) – Key quantity (default=1)
exception DoesNotExist
exception MultipleObjectsReturned
abs_cost
event

ForeignKey(related_name=”arbitraryfees”, on_delete=CASCADE(), to= BaseEvent)

event_id

Raw (integer) FK for event

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

key_name

CharField(max_length=64)

key_quantity

PositiveSmallIntegerField(default=1)

key_value

DecimalField(max_digits=8, decimal_places=2)

negative
objects = <django.db.models.manager.Manager object>
totalcost
class events.models.EventAttachment(id, event, attachment, note, externally_uploaded)[source]
Parameters:
  • id (AutoField) – Id (required)
  • event (ForeignKey to BaseEvent) – Event (required)
  • attachment (FileField) – Attachment (required)
  • note (TextField) – Note (default=)
  • externally_uploaded (BooleanField) – Externally uploaded (default=False)
  • for_service (ManyToManyField to Service) – For service (required)
exception DoesNotExist
exception MultipleObjectsReturned
attachment

The descriptor for the file attribute on the model instance. Return a FieldFile when accessed so you can write code like:

>>> from myapp.models import MyModel
>>> instance = MyModel.objects.get(pk=1)
>>> instance.file.size

Assign a file object on assignment so you can do:

>>> with open('/path/to/hello.world') as f:
...     instance.file = File(f)
event

ForeignKey(related_name=”attachments”, on_delete=CASCADE(), to= BaseEvent)

event_id

Raw (integer) FK for event

externally_uploaded

BooleanField(default=False)

for_service

Reverse Manager for events.EventAttachment’s for_service

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

note

TextField(blank=True, null=True, default=””)

objects = <django.db.models.manager.Manager object>
class events.models.EventCCInstance(*args, **kwargs)[source]

This is the crew chief instance for a particular event

Parameters:
  • id (AutoField) – Id (required)
  • event (ForeignKey to BaseEvent) – Event (required)
  • crew_chief (ForeignKey to User) – Crew chief (required)
  • category (ForeignKey to Category) – Category (required)
  • service (ForeignKey to Service) – Service
  • setup_location (ForeignKey to Location) – Setup location (required)
  • setup_start (DateTimeField) – Setup start
exception DoesNotExist
exception MultipleObjectsReturned
cal_desc()[source]

Description used by calendars

cal_end()[source]

End time used by calendars

cal_guid()[source]

Unique event id used by calendars

Link to display on calendars

cal_location()[source]

Location used by calendars

cal_name()[source]

Title used by calendars

cal_start()[source]

Start time used by calendars (setup)

category

ForeignKey(related_name=”ccinstances”, on_delete=PROTECT(), to= Category)

category_id

Raw (integer) FK for category

crew_chief

ForeignKey(related_name=”ccinstances”, on_delete=CASCADE(), to= User)

crew_chief_id

Raw (integer) FK for crew_chief

event

ForeignKey(related_name=”ccinstances”, on_delete=CASCADE(), to= BaseEvent)

event_id

Raw (integer) FK for event

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
service

ForeignKey(null=True, related_name=”ccinstances”, on_delete=PROTECT(), to= Service)

service_id

Raw (integer) FK for service

setup_location

ForeignKey(related_name=”ccinstances”, on_delete=PROTECT(), to= Location)

setup_location_id

Raw (integer) FK for setup_location

setup_start

DateTimeField(blank=True, null=True)

class events.models.EventManager[source]

This object consumes the output of the multi step workorder form

consume_workorder_formwiz(form_fields, wiz)[source]
class events.models.Extra(*args, **kwargs)[source]

An additional item or service to be added to an event (i.e. mirror ball)

Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – Name (required)
  • cost (DecimalField) – Cost (required)
  • desc (TextField) – Desc (required)
  • category (ForeignKey to Category) – Category (required)
  • disappear (BooleanField) – Disappear this extra instead of disable (default=False)
  • checkbox (BooleanField) – Use a checkbox instead of an integer entry (default=False)
  • services (ManyToManyField to Service) – Services (required)
exception DoesNotExist
exception MultipleObjectsReturned
category

ForeignKey(on_delete=PROTECT(), to= Category)

category_id

Raw (integer) FK for category

checkbox

BooleanField(default=False, help_text=”Use a checkbox instead of an integer entry”)

Checkbox: Use a checkbox instead of an integer entry

cost

DecimalField(max_digits=8, decimal_places=2)

desc

TextField()

disappear

BooleanField(default=False, help_text=”Disappear this extra instead of disable”)

Disappear: Disappear this extra instead of disable

extrainstance_set

Reverse Manager for events.ExtraInstance’s extra

formfield
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

name

CharField(max_length=64)

objects = <django.db.models.manager.Manager object>
services

Reverse Manager for events.Extra’s services

class events.models.ExtraInstance(*args, **kwargs)[source]

An instance of a given extra attached to an event

Parameters:
  • id (AutoField) – Id (required)
  • event (ForeignKey to BaseEvent) – Event (required)
  • extra (ForeignKey to Extra) – Extra (required)
  • quant (PositiveIntegerField) – Quant (required)
exception DoesNotExist
exception MultipleObjectsReturned
cost
event

ForeignKey(on_delete=CASCADE(), to= BaseEvent)

event_id

Raw (integer) FK for event

extra

ForeignKey(on_delete=PROTECT(), to= Extra)

extra_id

Raw (integer) FK for extra

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
quant

PositiveIntegerField()

totalcost
class events.models.Hours(*args, **kwargs)[source]

Number of hours a particular crew member put in working at a particular event

Parameters:
  • id (AutoField) – Id (required)
  • event (ForeignKey to BaseEvent) – Event (required)
  • category (ForeignKey to Category) – Category
  • service (ForeignKey to Service) – Service
  • user (ForeignKey to User) – User (required)
  • hours (DecimalField) – Hours
exception DoesNotExist
exception MultipleObjectsReturned
category

ForeignKey(blank=True, null=True, related_name=”hours”, on_delete=PROTECT(), to= Category)

category_id

Raw (integer) FK for category

event

ForeignKey(related_name=”hours”, on_delete=CASCADE(), to= BaseEvent)

event_id

Raw (integer) FK for event

hours

DecimalField(blank=True, null=True, max_digits=7, decimal_places=2)

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
service

ForeignKey(blank=True, null=True, related_name=”hours”, on_delete=PROTECT(), to= Service)

service_id

Raw (integer) FK for service

user

ForeignKey(related_name=”hours”, on_delete=CASCADE(), to= User)

user_id

Raw (integer) FK for user

class events.models.Lighting(id, shortname, longname, base_cost, addtl_cost, category, help_desc, enabled_event2012, enabled_event2019, service_ptr)[source]
Parameters:
  • id (AutoField) – Id (required)
  • shortname (CharField) – Shortname (required)
  • longname (CharField) – Longname (required)
  • base_cost (DecimalField) – Base cost (required)
  • addtl_cost (DecimalField) – Addtl cost (required)
  • category (ForeignKey to Category) – Category (required)
  • help_desc (TextField) – Help desc
  • enabled_event2012 (BooleanField) – Enabled for 2012 events (default=False)
  • enabled_event2019 (BooleanField) – Enabled for 2019 events (default=True)
  • service_ptr (OneToOneField to Service) – Service ptr (required)
exception DoesNotExist
exception MultipleObjectsReturned
lighting

Reverse Manager for events.Event’s lighting

service_ptr

OneToOneField(primary_key=True, serialize=False, auto_created=True, on_delete=CASCADE(), parent_link=True, to= Service)

service_ptr_id

Raw (integer) FK for service_ptr

class events.models.Location(*args, **kwargs)[source]

A place where an event, event setup or meeting can happen

Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – Name (required)
  • setup_only (BooleanField) – Setup only (default=False)
  • show_in_wo_form (BooleanField) – Event location (default=True)
  • available_for_meetings (BooleanField) – Available for meetings (default=False)
  • holds_equipment (BooleanField) – Holds equipment (default=False)
  • building (ForeignKey to Building) – Building (required)
exception DoesNotExist
exception MultipleObjectsReturned
available_for_meetings

BooleanField(default=False)

baseevent_set

Reverse Manager for events.BaseEvent’s location

building

ForeignKey(on_delete=CASCADE(), to= Building)

building_id

Raw (integer) FK for building

ccinstances

Reverse Manager for events.EventCCInstance’s setup_location

equipmentcategory_set

Reverse Manager for inventory.EquipmentCategory’s usual_place

equipmentitem_set

Reverse Manager for inventory.EquipmentItem’s home

holds_equipment

BooleanField(default=False)

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

meeting_set

Reverse Manager for meetings.Meeting’s location

name

CharField(max_length=64)

objects = <django.db.models.manager.Manager object>
office_hours

Reverse Manager for events.OfficeHour’s location

setup_only

BooleanField(default=False)

setuplocation

Reverse Manager for events.Event’s setup_location

show_in_wo_form

BooleanField(verbose_name=”Event Location”, default=True)

class events.models.MultiBilling(*args, **kwargs)[source]

A billing instance for multiple events that is sent to a client

Parameters:
  • id (AutoField) – Id (required)
  • date_billed (DateField) – Date billed (required)
  • date_paid (DateField) – Date paid
  • org (ForeignKey to Organization) – Org
  • amount (DecimalField) – Amount (required)
  • events (ManyToManyField to BaseEvent) – Events (required)
exception DoesNotExist
exception MultipleObjectsReturned
amount

DecimalField(max_digits=8, decimal_places=2)

date_billed

DateField()

date_paid

DateField(blank=True, null=True)

events

Reverse Manager for events.MultiBilling’s events

get_next_by_date_billed(*, field=<django.db.models.fields.DateField: date_billed>, is_next=True, **kwargs)
get_previous_by_date_billed(*, field=<django.db.models.fields.DateField: date_billed>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

multibillingemail_set

Reverse Manager for events.MultiBillingEmail’s multibilling

objects = <django.db.models.manager.Manager object>
org

ForeignKey(null=True, related_name=”multibillings”, on_delete=PROTECT(), to= Organization)

org_id

Raw (integer) FK for org

class events.models.MultiBillingEmail(*args, **kwargs)[source]

Billing information used in an email sent to a client (multiple events)

Parameters:
  • id (AutoField) – Id (required)
  • multibilling (ForeignKey to MultiBilling) – Multibilling (required)
  • subject (CharField) – Subject (required)
  • message (TextField) – Message (required)
  • sent_at (DateTimeField) – Sent at
  • email_to_users (ManyToManyField to User) – Email to users (required)
  • email_to_orgs (ManyToManyField to Organization) – Email to orgs (required)
exception DoesNotExist
exception MultipleObjectsReturned
email_to_orgs

Reverse Manager for events.MultiBillingEmail’s email_to_orgs

email_to_users

Reverse Manager for events.MultiBillingEmail’s email_to_users

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

message

TextField()

multibilling

ForeignKey(on_delete=CASCADE(), to= MultiBilling)

multibilling_id

Raw (integer) FK for multibilling

objects = <django.db.models.manager.Manager object>
sent_at

DateTimeField(null=True)

subject

CharField(max_length=128)

class events.models.OfficeHour(*args, **kwargs)[source]

A listing for an officer’s Office Hours

Parameters:
  • id (AutoField) – Id (required)
  • officer (ForeignKey to User) – Officer (required)
  • day (IntegerField) – Day (required)
  • hour_start (TimeField) – Start time (required)
  • hour_end (TimeField) – End time (required)
  • location (ForeignKey to Location) – Location (required)
exception DoesNotExist
exception MultipleObjectsReturned
day

IntegerField(choices=[(0, ‘Sunday’), (1, ‘Monday’), (2, ‘Tuesday’), (3, ‘Wednesday’), (4, ‘Thursday’), (5, ‘Friday’), (6, ‘Saturday’)])

get_day
get_day_display(*, field=<django.db.models.fields.IntegerField: day>)
hour_end

TimeField(verbose_name=”End Time”)

hour_start

TimeField(verbose_name=”Start Time”)

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

location

ForeignKey(related_name=”office_hours”, on_delete=CASCADE(), to= Location)

location_id

Raw (integer) FK for location

objects = <django.db.models.manager.Manager object>
officer

ForeignKey(on_delete=CASCADE(), to= User)

officer_id

Raw (integer) FK for officer

class events.models.OptimizedEventManager[source]
get_queryset()[source]

Return a new QuerySet object. Subclasses can override this method to customize the behavior of the Manager.

class events.models.OrgBillingVerificationEvent(id, org, date, verified_by, note)[source]
Parameters:
  • id (AutoField) – Id (required)
  • org (ForeignKey to Organization) – Org (required)
  • date (DateField) – Date (required)
  • verified_by (ForeignKey to User) – Verified by (required)
  • note (TextField) – Note
exception DoesNotExist
exception MultipleObjectsReturned
date

DateField()

get_next_by_date(*, field=<django.db.models.fields.DateField: date>, is_next=True, **kwargs)
get_previous_by_date(*, field=<django.db.models.fields.DateField: date>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

note

TextField(blank=True, null=True)

objects = <django.db.models.manager.Manager object>
org

ForeignKey(related_name=”verifications”, on_delete=CASCADE(), to= Organization)

org_id

Raw (integer) FK for org

verified_by

ForeignKey(related_name=”verification_events”, on_delete=CASCADE(), to= User)

verified_by_id

Raw (integer) FK for verified_by

class events.models.Organization(*args, **kwargs)[source]

AKA: A Client

Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – Name (required)
  • shortname (CharField) – Shortname
  • email (EmailField) – Normal_email_unused
  • exec_email (EmailField) – Email
  • email_exec (BooleanField) – Email exec (default=True)
  • email_normal (BooleanField) – Email normal (default=False)
  • address (TextField) – Address
  • phone (CharField) – Phone (required)
  • workday_fund (IntegerField) – Workday fund
  • worktag (CharField) – Worktag
  • user_in_charge (ForeignKey to User) – User in charge (required)
  • notes (TextField) – Notes
  • personal (BooleanField) – Personal (default=False)
  • delinquent (BooleanField) – Delinquent (default=False)
  • last_updated (DateTimeField) – Last updated (required)
  • archived (BooleanField) – Archived (default=False)
  • locked (BooleanField) – Locked (default=False)
  • associated_users (ManyToManyField to User) – Associated users (required)
  • associated_orgs (ManyToManyField to Organization) – Associated clients (required)
exception DoesNotExist
exception MultipleObjectsReturned
address

TextField(blank=True, null=True)

archived

BooleanField(default=False)

associated_orgs

Reverse Manager for events.Organization’s associated_orgs

associated_users

Reverse Manager for events.Organization’s associated_users

billedevents

Reverse Manager for events.BaseEvent’s billing_org

billingemail_set

Reverse Manager for events.BillingEmail’s email_to_orgs

delinquent

BooleanField(default=False)

email

CharField(verbose_name=”normal_email_unused”, max_length=254, blank=True, null=True)

email_exec

BooleanField(default=True)

email_normal

BooleanField(default=False)

eventcount
events

Reverse Manager for events.BaseEvent’s org

exec_email

CharField(verbose_name=”Email”, max_length=254, null=True)

get_absolute_url()[source]
get_next_by_last_updated(*, field=<django.db.models.fields.DateTimeField: last_updated>, is_next=True, **kwargs)
get_previous_by_last_updated(*, field=<django.db.models.fields.DateTimeField: last_updated>, is_next=False, **kwargs)
get_workday_fund_display(*, field=<django.db.models.fields.IntegerField: workday_fund>)
glyphicon = 'education'
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

last_updated

DateTimeField(auto_now=True)

locked

BooleanField(blank=True, default=False)

multibillingemail_set

Reverse Manager for events.MultiBillingEmail’s email_to_orgs

multibillings

Reverse Manager for events.MultiBilling’s org

name

CharField(max_length=128, unique=True)

notes

TextField(blank=True, null=True)

objects = <django.db.models.manager.Manager object>
organizationtransfer_set

Reverse Manager for events.OrganizationTransfer’s org

personal

BooleanField(default=False)

phone

CharField(max_length=32)

retname
shortname

CharField(max_length=8, blank=True, null=True)

user_in_charge

ForeignKey(related_name=”orgowner”, on_delete=PROTECT(), to= User)

user_in_charge_id

Raw (integer) FK for user_in_charge

verifications

Reverse Manager for events.OrgBillingVerificationEvent’s org

workday_fund

IntegerField(blank=True, null=True, choices=[(810, ‘Student Organization (810-FD)’), (110, ‘Operating (110-FD)’), (220, ‘Gift (220-FD)’), (250, ‘Gift (250-FD)’), (500, ‘Gift (500-FD)’), (210, ‘Grant (210-FD)’), (900, ‘Project (900-FD)’), (120, ‘Designated (120-FD)’)])

worktag

CharField(max_length=10, blank=True, null=True)

class events.models.OrganizationTransfer(*args, **kwargs)[source]

Record of a transfer of ownership between two users for a particular organization

Parameters:
  • id (AutoField) – Id (required)
  • initiator (ForeignKey to User) – Initiator (required)
  • new_user_in_charge (ForeignKey to User) – New user in charge (required)
  • old_user_in_charge (ForeignKey to User) – Old user in charge (required)
  • org (ForeignKey to Organization) – Org (required)
  • uuid (UUIDField) – Uuid (required)
  • created (DateTimeField) – Created (required)
  • completed_on (DateTimeField) – Completed on
  • expiry (DateTimeField) – Expiry
  • completed (BooleanField) – Completed (default=False)
exception DoesNotExist
exception MultipleObjectsReturned
completed

BooleanField(default=False)

completed_on

DateTimeField(blank=True, null=True)

created

DateTimeField(auto_now=True)

expiry

DateTimeField(blank=True, null=True)

get_next_by_created(*, field=<django.db.models.fields.DateTimeField: created>, is_next=True, **kwargs)
get_previous_by_created(*, field=<django.db.models.fields.DateTimeField: created>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

initiator

ForeignKey(related_name=”xfer_initiated”, on_delete=CASCADE(), to= User)

initiator_id

Raw (integer) FK for initiator

is_expired
new_user_in_charge

ForeignKey(related_name=”xfer_new”, on_delete=CASCADE(), to= User)

new_user_in_charge_id

Raw (integer) FK for new_user_in_charge

objects = <django.db.models.manager.Manager object>
old_user_in_charge

ForeignKey(related_name=”xfer_old”, on_delete=CASCADE(), to= User)

old_user_in_charge_id

Raw (integer) FK for old_user_in_charge

org

ForeignKey(on_delete=CASCADE(), to= Organization)

org_id

Raw (integer) FK for org

uuid

UUIDField()

class events.models.PostEventSurvey(*args, **kwargs)[source]

Survey sent to clients after an event to collect their feedback

Parameters:
  • id (AutoField) – Id (required)
  • event (ForeignKey to BaseEvent) – Event (required)
  • person (ForeignKey to User) – Person (required)
  • services_quality (IntegerField) – Please rate the overall quality of the services lens and lights provided. (required)
  • lighting_quality (IntegerField) – How satisfied were you with the lighting? (required)
  • sound_quality (IntegerField) – How satisfied were you with the sound system? (required)
  • work_order_method (IntegerField) – How did you submit the workorder? (required)
  • work_order_experience (IntegerField) – How would you rate your overall experience using the workorder tool? (default=-1)
  • work_order_ease (IntegerField) – How would you rate the workorder tool’s clarity and ease of use? (default=-1)
  • work_order_comments (TextField) – Please provide any additional comments you may have regarding your experience with the workorder tool. is there anything you would like to see us improve? (required)
  • communication_responsiveness (IntegerField) – Lens and lights was responsive to my communications. (required)
  • pricelist_ux (IntegerField) – It was easy to determine which services to request and i had no problem finding what i needed. (required)
  • setup_on_time (IntegerField) – My event was set up and the crew was ready on time. (required)
  • crew_respectfulness (IntegerField) – When interacting with the crew, they were helpful and respectful. (required)
  • price_appropriate (IntegerField) – The price quoted for the event matched my expectations and was appropriate for the services provided. (required)
  • customer_would_return (IntegerField) – I would use lens and lights in the future. (required)
  • comments (TextField) – Please use this area to provide any additional feedback you may have about your event. (required)
exception DoesNotExist
exception MultipleObjectsReturned
comments

TextField(verbose_name=”Please use this area to provide any additional feedback you may have about your event.”, blank=True)

communication_responsiveness

IntegerField(verbose_name=”Lens and Lights was responsive to my communications.”, choices=[(-1, ‘Not applicable’), (0, ‘Strongly disagree’), (1, ‘Disagree’), (2, ‘Neither agree nor disagree’), (3, ‘Agree’), (4, ‘Strongly agree’)])

crew_respectfulness

IntegerField(verbose_name=”When interacting with the crew, they were helpful and respectful.”, choices=[(-1, ‘Not applicable’), (0, ‘Strongly disagree’), (1, ‘Disagree’), (2, ‘Neither agree nor disagree’), (3, ‘Agree’), (4, ‘Strongly agree’)])

customer_would_return

IntegerField(verbose_name=”I would use Lens and Lights in the future.”, choices=[(-1, ‘Not applicable’), (0, ‘Strongly disagree’), (1, ‘Disagree’), (2, ‘Neither agree nor disagree’), (3, ‘Agree’), (4, ‘Strongly agree’)])

event

ForeignKey(related_name=”surveys”, on_delete=PROTECT(), to= BaseEvent)

event_id

Raw (integer) FK for event

get_communication_responsiveness_display(*, field=<django.db.models.fields.IntegerField: communication_responsiveness>)
get_crew_respectfulness_display(*, field=<django.db.models.fields.IntegerField: crew_respectfulness>)
get_customer_would_return_display(*, field=<django.db.models.fields.IntegerField: customer_would_return>)
get_lighting_quality_display(*, field=<django.db.models.fields.IntegerField: lighting_quality>)
get_price_appropriate_display(*, field=<django.db.models.fields.IntegerField: price_appropriate>)
get_pricelist_ux_display(*, field=<django.db.models.fields.IntegerField: pricelist_ux>)
get_services_quality_display(*, field=<django.db.models.fields.IntegerField: services_quality>)
get_setup_on_time_display(*, field=<django.db.models.fields.IntegerField: setup_on_time>)
get_sound_quality_display(*, field=<django.db.models.fields.IntegerField: sound_quality>)
get_work_order_ease_display(*, field=<django.db.models.fields.IntegerField: work_order_ease>)
get_work_order_experience_display(*, field=<django.db.models.fields.IntegerField: work_order_experience>)
get_work_order_method_display(*, field=<django.db.models.fields.IntegerField: work_order_method>)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

lighting_quality

IntegerField(verbose_name=”How satisfied were you with the lighting?”, choices=[(-1, ‘Not applicable’), (0, ‘Poor’), (1, ‘Fair’), (2, ‘Good’), (3, ‘Very good’), (4, ‘Excellent’)])

objects = <django.db.models.manager.Manager object>
person

ForeignKey(related_name=”surveys”, on_delete=PROTECT(), to= User)

person_id

Raw (integer) FK for person

price_appropriate

IntegerField(verbose_name=”The price quoted for the event matched my expectations and was appropriate for the services provided.”, choices=[(-1, ‘Not applicable’), (0, ‘Strongly disagree’), (1, ‘Disagree’), (2, ‘Neither agree nor disagree’), (3, ‘Agree’), (4, ‘Strongly agree’)])

pricelist_ux

IntegerField(verbose_name=”It was easy to determine which services to request and I had no problem finding what I needed.”, choices=[(-1, ‘Not applicable’), (0, ‘Strongly disagree’), (1, ‘Disagree’), (2, ‘Neither agree nor disagree’), (3, ‘Agree’), (4, ‘Strongly agree’)])

services_quality

IntegerField(verbose_name=”Please rate the overall quality of the services Lens and Lights provided.”, choices=[(-1, ‘Not applicable’), (0, ‘Poor’), (1, ‘Fair’), (2, ‘Good’), (3, ‘Very good’), (4, ‘Excellent’)])

setup_on_time

IntegerField(verbose_name=”My event was set up and the crew was ready on time.”, choices=[(-1, ‘Not applicable’), (0, ‘Strongly disagree’), (1, ‘Disagree’), (2, ‘Neither agree nor disagree’), (3, ‘Agree’), (4, ‘Strongly agree’)])

sound_quality

IntegerField(verbose_name=”How satisfied were you with the sound system?”, choices=[(-1, ‘Not applicable’), (0, ‘Poor’), (1, ‘Fair’), (2, ‘Good’), (3, ‘Very good’), (4, ‘Excellent’)])

work_order_comments

TextField(verbose_name=”Please provide any additional comments you may have regarding your experience with the workorder tool. Is there anything you would like to see us improve?”, blank=True)

work_order_ease

IntegerField(verbose_name=”How would you rate the workorder tool’s clarity and ease of use?”, blank=True, null=True, default=-1, choices=[(-1, ‘Not applicable’), (0, ‘Poor’), (1, ‘Fair’), (2, ‘Good’), (3, ‘Very good’), (4, ‘Excellent’)])

work_order_experience

IntegerField(verbose_name=”How would you rate your overall experience using the workorder tool?”, blank=True, null=True, default=-1, choices=[(-1, ‘Not applicable’), (0, ‘Poor’), (1, ‘Fair’), (2, ‘Good’), (3, ‘Very good’), (4, ‘Excellent’)])

work_order_method

IntegerField(verbose_name=”How did you submit the workorder?”, choices=[(None, ‘Please select…’), (1, ‘Via the website at lnl.wpi.edu/workorder’), (2, ‘Emailed lnl@wpi.edu’), (3, ‘Emailed an LNL representative directly’), (4, ‘By phone’), (5, ‘In person’), (0, ‘Other’), (-1, “I don’t know”)])

class events.models.Projection(id, shortname, longname, base_cost, addtl_cost, category, help_desc, enabled_event2012, enabled_event2019, service_ptr)[source]
Parameters:
  • id (AutoField) – Id (required)
  • shortname (CharField) – Shortname (required)
  • longname (CharField) – Longname (required)
  • base_cost (DecimalField) – Base cost (required)
  • addtl_cost (DecimalField) – Addtl cost (required)
  • category (ForeignKey to Category) – Category (required)
  • help_desc (TextField) – Help desc
  • enabled_event2012 (BooleanField) – Enabled for 2012 events (default=False)
  • enabled_event2019 (BooleanField) – Enabled for 2019 events (default=True)
  • service_ptr (OneToOneField to Service) – Service ptr (required)
exception DoesNotExist
exception MultipleObjectsReturned
projection

Reverse Manager for events.Event’s projection

service_ptr

OneToOneField(primary_key=True, serialize=False, auto_created=True, on_delete=CASCADE(), parent_link=True, to= Service)

service_ptr_id

Raw (integer) FK for service_ptr

class events.models.ReportReminder(*args, **kwargs)[source]

A log of CC Report Reminders sent

Parameters:
  • id (AutoField) – Id (required)
  • event (ForeignKey to BaseEvent) – Event (required)
  • crew_chief (ForeignKey to User) – Crew chief (required)
  • sent (DateTimeField) – Sent (required)
exception DoesNotExist
exception MultipleObjectsReturned
crew_chief

ForeignKey(related_name=”ccreportreminders”, on_delete=CASCADE(), to= User)

crew_chief_id

Raw (integer) FK for crew_chief

event

ForeignKey(related_name=”ccreportreminders”, on_delete=CASCADE(), to= BaseEvent)

event_id

Raw (integer) FK for event

get_next_by_sent(*, field=<django.db.models.fields.DateTimeField: sent>, is_next=True, **kwargs)
get_previous_by_sent(*, field=<django.db.models.fields.DateTimeField: sent>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
sent

DateTimeField(auto_now_add=True)

class events.models.Service(*args, **kwargs)[source]

Some chargable service that is added to an event; lighting, sound, projection are examples

Parameters:
  • id (AutoField) – Id (required)
  • shortname (CharField) – Shortname (required)
  • longname (CharField) – Longname (required)
  • base_cost (DecimalField) – Base cost (required)
  • addtl_cost (DecimalField) – Addtl cost (required)
  • category (ForeignKey to Category) – Category (required)
  • help_desc (TextField) – Help desc
  • enabled_event2012 (BooleanField) – Enabled for 2012 events (default=False)
  • enabled_event2019 (BooleanField) – Enabled for 2019 events (default=True)
exception DoesNotExist
exception MultipleObjectsReturned
addtl_cost

DecimalField(max_digits=8, decimal_places=2)

attachments

Reverse Manager for events.EventAttachment’s for_service

base_cost

DecimalField(max_digits=8, decimal_places=2)

category

ForeignKey(on_delete=PROTECT(), to= Category)

category_id

Raw (integer) FK for category

ccinstances

Reverse Manager for events.EventCCInstance’s service

enabled_event2012

BooleanField(verbose_name=”Enabled for 2012 Events”, default=False)

enabled_event2019

BooleanField(verbose_name=”Enabled for 2019 Events”, default=True)

event_set

Reverse Manager for events.Event’s otherservices

extra_set

Reverse Manager for events.Extra’s services

help_desc

TextField(blank=True, null=True)

hours

Reverse Manager for events.Hours’s service

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

lighting

Accessor to the related object on the reverse side of a one-to-one relation.

In the example:

class Restaurant(Model):
    place = OneToOneField(Place, related_name='restaurant')

Place.restaurant is a ReverseOneToOneDescriptor instance.

longname

CharField(max_length=64)

objects = <django.db.models.manager.Manager object>
projection

Accessor to the related object on the reverse side of a one-to-one relation.

In the example:

class Restaurant(Model):
    place = OneToOneField(Place, related_name='restaurant')

Place.restaurant is a ReverseOneToOneDescriptor instance.

serviceinstance_set

Reverse Manager for events.ServiceInstance’s service

shortname

CharField(max_length=2)

sound

Accessor to the related object on the reverse side of a one-to-one relation.

In the example:

class Restaurant(Model):
    place = OneToOneField(Place, related_name='restaurant')

Place.restaurant is a ReverseOneToOneDescriptor instance.

class events.models.ServiceInstance(*args, **kwargs)[source]

An instance of a service associated with a specific event. Created with Event2019

Parameters:
  • id (AutoField) – Id (required)
  • service (ForeignKey to Service) – Service (required)
  • event (ForeignKey to BaseEvent) – Event (required)
  • detail (TextField) – Detail (required)
exception DoesNotExist
exception MultipleObjectsReturned
detail

TextField(blank=True)

event

ForeignKey(on_delete=CASCADE(), to= BaseEvent)

event_id

Raw (integer) FK for event

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
service

ForeignKey(on_delete=PROTECT(), to= Service)

service_id

Raw (integer) FK for service

class events.models.Sound(id, shortname, longname, base_cost, addtl_cost, category, help_desc, enabled_event2012, enabled_event2019, service_ptr)[source]
Parameters:
  • id (AutoField) – Id (required)
  • shortname (CharField) – Shortname (required)
  • longname (CharField) – Longname (required)
  • base_cost (DecimalField) – Base cost (required)
  • addtl_cost (DecimalField) – Addtl cost (required)
  • category (ForeignKey to Category) – Category (required)
  • help_desc (TextField) – Help desc
  • enabled_event2012 (BooleanField) – Enabled for 2012 events (default=False)
  • enabled_event2019 (BooleanField) – Enabled for 2019 events (default=True)
  • service_ptr (OneToOneField to Service) – Service ptr (required)
exception DoesNotExist
exception MultipleObjectsReturned
service_ptr

OneToOneField(primary_key=True, serialize=False, auto_created=True, on_delete=CASCADE(), parent_link=True, to= Service)

service_ptr_id

Raw (integer) FK for service_ptr

sound

Reverse Manager for events.Event’s sound

class events.models.Workshop(*args, **kwargs)[source]

A Workshop series hosted by LNL

Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – Name (required)
  • instructors (CharField) – Instructors (required)
  • description (TextField) – Description (required)
  • location (CharField) – Location (required)
  • notes (TextField) – Notes
exception DoesNotExist
exception MultipleObjectsReturned
dates

Reverse Manager for events.WorkshopDate’s workshop

description

TextField()

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

instructors

CharField(max_length=100)

location

CharField(max_length=100)

name

CharField(max_length=128)

notes

TextField(blank=True, null=True)

objects = <django.db.models.manager.Manager object>
class events.models.WorkshopDate(id, workshop, date)[source]
Parameters:
  • id (AutoField) – Id (required)
  • workshop (ForeignKey to Workshop) – Workshop (required)
  • date (DateTimeField) – Date (required)
exception DoesNotExist
exception MultipleObjectsReturned
date

DateTimeField()

get_next_by_date(*, field=<django.db.models.fields.DateTimeField: date>, is_next=True, **kwargs)
get_previous_by_date(*, field=<django.db.models.fields.DateTimeField: date>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
workshop

ForeignKey(related_name=”dates”, on_delete=CASCADE(), to= Workshop)

workshop_id

Raw (integer) FK for workshop

events.models.attachment_file_name(instance, filename)[source]
events.models.consume_event_method(emethod, methodname)[source]
events.models.get_host()[source]
events.models.get_level_object(level, etype)[source]

Views

class events.views.flow.BillingCreate(**kwargs)[source]
dispatch(request, *args, **kwargs)[source]
form_class

alias of events.forms.BillingForm

form_valid(form)[source]

If the form is valid, save the associated model.

get_context_data(**kwargs)[source]

Insert the form into the context dict.

get_form_kwargs()[source]

Return the keyword arguments for instantiating the form.

get_success_url()[source]

Return the URL to redirect to after processing a valid form.

model

alias of events.models.Billing

msg = 'New Bill'
perms = 'events.bill_event'
template_name = 'form_crispy_cbv.html'
class events.views.flow.BillingDelete(**kwargs)[source]
dispatch(request, *args, **kwargs)[source]
get_object(*args, **kwargs)[source]

Validate preconditions for deleting a bill

get_success_url()[source]
model

alias of events.models.Billing

msg = 'Delete Bill'
perms = 'events.bill_event'
template_name = 'form_delete_cbv.html'
class events.views.flow.BillingEmailCreate(**kwargs)[source]
dispatch(request, *args, **kwargs)[source]
form_class

alias of events.forms.BillingEmailForm

form_valid(form)[source]

If the form is valid, save the associated model.

get_form_kwargs()[source]

Return the keyword arguments for instantiating the form.

get_success_url()[source]

Return the URL to redirect to after processing a valid form.

model

alias of events.models.BillingEmail

msg = 'New Billing Email'
perms = 'events.bill_event'
template_name = 'form_crispy.html'
class events.views.flow.BillingUpdate(**kwargs)[source]
dispatch(request, *args, **kwargs)[source]
form_class

alias of events.forms.BillingUpdateForm

form_valid(form)[source]

If the form is valid, save the associated model.

get_form_kwargs()[source]

Return the keyword arguments for instantiating the form.

get_object(*args, **kwargs)[source]

Validate preconditions for editing a bill

get_success_url()[source]

Return the URL to redirect to after processing a valid form.

model

alias of events.models.Billing

msg = 'Update Bill'
perms = 'events.bill_event'
template_name = 'form_crispy_cbv.html'
class events.views.flow.CCRCreate(**kwargs)[source]

Create a new crew chief report

dispatch(request, *args, **kwargs)[source]
form_class

alias of events.forms.InternalReportForm

form_valid(form)[source]

If the form is valid, save the associated model.

get_form_kwargs()[source]

Return the keyword arguments for instantiating the form.

get_success_url()[source]

Return the URL to redirect to after processing a valid form.

model

alias of events.models.CCReport

msg = 'New Crew Chief Report'
perms = 'events.add_event_report'
template_name = 'form_crispy_cbv.html'
user_passes_test(request, *args, **kwargs)[source]
class events.views.flow.CCRDelete(**kwargs)[source]

Delete a crew chief report

get_object(queryset=None)[source]

Hook to ensure object isn’t closed

get_success_url()[source]
model

alias of events.models.CCReport

msg = 'Delete Crew Chief Report'
perms = 'events.delete_ccreport'
template_name = 'form_delete_cbv.html'
user_passes_test(request, *args, **kwargs)[source]
class events.views.flow.CCRUpdate(**kwargs)[source]

Update an existing crew chief report

form_class

alias of events.forms.InternalReportForm

form_valid(form)[source]

If the form is valid, save the associated model.

get_form_kwargs()[source]

Return the keyword arguments for instantiating the form.

get_success_url()[source]

Return the URL to redirect to after processing a valid form.

model

alias of events.models.CCReport

msg = 'Update Crew Chief Report'
perms = 'events.change_ccreport'
template_name = 'form_crispy_cbv.html'
user_passes_test(request, *args, **kwargs)[source]
class events.views.flow.MultiBillingCreate(**kwargs)[source]
form_class

alias of events.forms.MultiBillingForm

form_valid(form)[source]

If the form is valid, save the associated model.

get_form_kwargs()[source]

Return the keyword arguments for instantiating the form.

get_success_url()[source]

Return the URL to redirect to after processing a valid form.

model

alias of events.models.MultiBilling

msg = 'New MultiBill'
perms = 'events.bill_event'
template_name = 'form_crispy.html'
class events.views.flow.MultiBillingDelete(**kwargs)[source]
get_object(*args, **kwargs)[source]

Validate preconditions for deleting a multibill

get_success_url()[source]
model

alias of events.models.MultiBilling

msg = 'Delete MultiBill'
perms = 'events.bill_event'
template_name = 'form_delete_cbv.html'
class events.views.flow.MultiBillingEmailCreate(**kwargs)[source]
dispatch(request, *args, **kwargs)[source]
form_class

alias of events.forms.MultiBillingEmailForm

form_valid(form)[source]

If the form is valid, save the associated model.

get_form_kwargs()[source]

Return the keyword arguments for instantiating the form.

get_success_url()[source]

Return the URL to redirect to after processing a valid form.

model

alias of events.models.MultiBillingEmail

msg = 'New Billing Email'
perms = 'events.bill_event'
template_name = 'form_crispy.html'
class events.views.flow.MultiBillingUpdate(**kwargs)[source]
form_class

alias of events.forms.MultiBillingUpdateForm

form_valid(form)[source]

If the form is valid, save the associated model.

get_object(*args, **kwargs)[source]

Validate preconditions for editing a multibill

get_success_url()[source]

Return the URL to redirect to after processing a valid form.

model

alias of events.models.MultiBilling

msg = 'Update MultiBill'
perms = 'events.bill_event'
template_name = 'form_crispy.html'
class events.views.flow.WorkdayEntry(**kwargs)[source]
dispatch(request, *args, **kwargs)[source]
form_class

alias of events.forms.WorkdayForm

form_valid(form)[source]

If the form is valid, save the associated model.

get_initial()[source]

Return the initial data to use for forms on this view.

get_success_url()[source]

Return the URL to redirect to after processing a valid form.

model

alias of events.models.Event2019

perms = 'events.edit_org_billing'
template_name = 'form_crispy_workday.html'
user_passes_test(request, *args, **kwargs)[source]
events.views.flow.approval(request, id)[source]

Approve an event (agree to provide services for the event)

events.views.flow.assignattach(request, id)[source]

Update attachments for an event (file uploads)

events.views.flow.assignattach_external(request, id)[source]

Update attachments for an event (client-view)

events.views.flow.assigncc(request, id)[source]

Assign crew chiefs to an event

events.views.flow.assigncrew(request, id)[source]
  • Pre-2019 Events: Assign crew members to an event
  • Newer Events: Redirect to crew list
events.views.flow.bulk_checkin(request)[source]

Scan or swipe a registered WPI ID to checkin or checkout of an event as a crew member

events.views.flow.cancel(request, id)[source]

Cancel an event (LNL will no longer provide services for this event). POST only.

events.views.flow.checkin(request)[source]

Event checkin page for crew members

events.views.flow.checkout(request)[source]

Event checkout page for crew members

events.views.flow.close(request, id)[source]

Close an event (not to be confused with cancel). POST only.

events.views.flow.crew_tracker(request)[source]

Event checkin / checkout menu for crew members. GET requests only.

events.views.flow.denial(request, id)[source]

Deny an incoming event (LNL will not provide services for the event)

events.views.flow.download_ics(request, pk)[source]

Generate and download an ics file

events.views.flow.extras(request, id)[source]

This form is for adding extras to an event

events.views.flow.hours_bulk_admin(request, id)[source]

Update crew member hours in bulk

events.views.flow.hours_prefill_self(request, id)[source]

Log the current user as a crew member for an event. This only works after setup begins and will continue to work up until 3 hours after the event. GET requests only.

events.views.flow.mark_entered_into_workday(request, id)[source]

Marks an event as entered into Workday. POST only.

events.views.flow.oneoff(request, id)[source]

This form is for adding oneoff fees to an event

events.views.flow.pay_bill(request, event, pk)[source]

Quietly pays a bill, showing a message on the next page. POST only.

events.views.flow.remindall(request, id)[source]

Remind any crew chiefs who have not yet completed a CC report for a particular event to do so

events.views.flow.reopen(request, id)[source]

Reopen an event that has already been closed. POST only.

events.views.flow.review(request, id)[source]

Review an event for billing

events.views.flow.reviewremind(request, id, uid)[source]

Remind a crew chief to complete their CC report

Parameters:
  • id – The primary key value of the respective event
  • uid – The primary key value of the user to send a reminder to
events.views.flow.rmcc(request, id, user)[source]

Remove a crew chief from an event (pre-2019 events only)

Parameters:
  • id – The primary key value of the event
  • user – The primary key value of the user
events.views.flow.rmcrew(request, id, user)[source]

Remove a user from the list of crew members who attended an event (pre-2019 events only)

Parameters:
  • id – The primary key value of the event
  • user – The primary key value of the user
events.views.flow.viewevent(request, id)[source]

View event details

events.views.indices.admin(request, msg=None)[source]

Member landing page

events.views.indices.dbg_land(request)[source]
events.views.indices.index(request)[source]

Landing Page

events.views.indices.survey_dashboard(request)[source]

Dashboard for post-event survey results

events.views.indices.workshops(request)[source]

Public workshops page

class events.views.list.DeleteWorkshop(**kwargs)[source]

Delete a series of workshops

get_success_url()[source]
model

alias of events.models.Workshop

msg = 'Delete Workshop'
perms = 'events.edit_workshops'
template_name = 'form_delete_cbv.html'
class events.views.list.FakeExtendedField(name, model=<class 'events.models.BaseEvent'>, favicon=None, verbose_name=None, sortable=True)[source]

Just a shim to make things clear, using getattr magic to make python think it’s the original field Use it if you want to change something about a field

class events.views.list.FakeField(name, verbose_name=None, favicon=None, sortable=False)[source]

Means that there is some check for it in the template end or that the thing is a property instead of a field

events.views.list.all(request, start=None, end=None)[source]

Lists all events

events.views.list.all_cal(request, start=None, end=None)[source]

Calendar view for all events

events.views.list.awaitingworkday(request, start=None, end=None)[source]

Lists events that are waiting to be entered into Workday

events.views.list.build_redirect(request, **kwargs)[source]

Add query string to URL

events.views.list.closed(request, start=None, end=None)[source]

Lists closed events

events.views.list.closed_cal(request, start=None, end=None)[source]

Calendar view for closed events

events.views.list.datefilter(eventqs, context, start=None, end=None)[source]

Generic date filtering

events.views.list.edit_workshop(request, pk)[source]

Form to edit the details for a workshop series

events.views.list.filter_events(request, context, events, start, end, prefetch_org=False, prefetch_cc=False, prefetch_billing=False, hide_unapproved=False, event2019=False, sort='-datetime_start')[source]

Filter a queryset of events based on specified criteria

Parameters:
  • request – The calling view’s request object
  • context – The calling view’s current context dictionary
  • events – Queryset of events to filter
  • start – Datetime to compare event start times to
  • end – Datetime to compare event end times to
  • prefetch_org – Boolean - If true, prefetch related items based on client
  • prefetch_cc – Boolean - If true, prefetch related items based on client or crew chiefs and select related items based on building
  • prefetch_billing – Boolean - If true, prefetch related items based on client or crew chiefs and select related items based on building
  • hide_unapproved – Boolean - If true, exclude events that have not been approved
  • event2019 – Boolean - If true, queryset only contains Event2019 objects
  • sort – String - Default field to sort by (prepend “-” for reverse)
Returns:

Queryset of events and updated context dictionary

events.views.list.findchief(request, start=None, end=None)[source]

Lists any events that have been approved and need crew chiefs

events.views.list.findchief_cal(request, start=None, end=None)[source]

Calendar view for events that need crew chiefs

events.views.list.generate_response(request, context, start, end, time_range_unspecified)[source]

Build an event list view response object and set cookies if necessary

Parameters:
  • request – The calling view’s request object
  • context – The calling view’s context dictionary
  • start – Datetime used to filter the events (Optional)
  • end – Datetime used to filter the events (Optional)
  • time_range_unspecified – Boolean - If true, will ignore start and end times
Returns:

Response object

events.views.list.get_very_large_date_range()[source]

Helper function to return start and end that go very far into past and future

events.views.list.incoming(request, start=None, end=None)[source]

Lists all incoming events (not yet approved)

events.views.list.incoming_cal(request, start=None, end=None)[source]

Calendar view of incoming events

events.views.list.map_fields(cols)[source]

Puts field names into actual fields (even if they don’t exist)

events.views.list.multibillings(request)[source]

Lists all multibills

events.views.list.new_workshop(request)[source]

Form to add a new workshop series

events.views.list.openworkorders(request, start=None, end=None)[source]

Lists open events (not cancelled or otherwise closed)

events.views.list.openworkorders_cal(request, start=None, end=None)[source]

Calendar view for open events

events.views.list.paginate_helper(queryset, page, sort=None, count=40)[source]
events.views.list.paid(request, start=None, end=None)[source]

Lists events where all bills have been paid

events.views.list.paid_cal(request, start=None, end=None)[source]

Calendar view for events that have already been paid

events.views.list.public_facing(request)[source]

Lists events that have been approved, have not yet ended, and can otherwise be viewed by anyone (i.e. no sensitive or test events)

events.views.list.unbilled(request, start=None, end=None)[source]

Lists events that are ready to be billed

events.views.list.unbilled_cal(request, start=None, end=None)[source]

Calendar view for events that have yet to be billed

events.views.list.unbilled_semester(request, start=None, end=None)[source]

Lists events that have yet to be billed and are set to be billed in bulk

events.views.list.unbilled_semester_cal(request, start=None, end=None)[source]

Calendar view for events that have yet to be billed and are set to be billed in bulk

events.views.list.unpaid(request, start=None, end=None)[source]

Lists events that have unpaid bills

events.views.list.unpaid_cal(request, start=None, end=None)[source]

Calendar view for events that have unpaid bills

events.views.list.unpaid_workday(request, start=None, end=None)[source]

Lists events that have been entered into workday but have not yet been paid for

events.views.list.unreviewed(request, start=None, end=None)[source]

Lists events that are pending review for billing

events.views.list.unreviewed_cal(request, start=None, end=None)[source]

Calendar view for events that are ready to be reviewed for billing

events.views.list.upcoming(request, start=None, end=None)[source]

Lists Upcoming Events

If start and end are both None, then it’ll show all upcoming events for the next 15 days

events.views.list.workshop_dates(request, pk)[source]

Form to add / edit sessions (dates) for a workshop series

events.views.list.workshops_list(request)[source]

List all workshop series

events.views.mkedrm.clear_to_send(to, triggered_by, fields_edited)[source]

Helper function to determine if a user should receive an Event Edited notification

Parameters:
  • to – The user the message would be sent to
  • triggered_by – The user that edited the event
  • fields_edited – A list of edited fields
Returns:

A list of approved communication methods

events.views.mkedrm.eventnew(request, id=None)[source]

Create or edit an event

Parameters:id – Defaults to None (create a new event). Otherwise, this is the primary key value of the event you intend to edit
class events.views.my.PostEventSurveyCreate(**kwargs)[source]
dispatch(request, *args, **kwargs)[source]
form_class

alias of events.forms.PostEventSurveyForm

form_valid(form)[source]

If the form is valid, save the associated model.

get_context_data(**kwargs)[source]

Insert the form into the context dict.

get_form_kwargs()[source]

Return the keyword arguments for instantiating the form.

get_success_url()[source]

Return the URL to redirect to after processing a valid form.

model

alias of events.models.PostEventSurvey

template_name = 'form_crispy_survey.html'
events.views.my.ccreport(request, eventid)[source]

Submits a crew chief report

events.views.my.eventfiles(request, eventid)[source]
events.views.my.hours_bulk(request, eventid)[source]

Bulk Hours Entry Form

events.views.my.hours_edit(request, eventid, userid)[source]

Hour Entry Form for CC (editing)

events.views.my.hours_list(request, eventid)[source]

Lists a user’s work hours

events.views.my.hours_mk(request, eventid)[source]

Hour Entry Form for CC

events.views.my.myevents(request)[source]

Lists events that a user has CC’d or been involved with

events.views.my.myorgform(request)[source]

Organization Creation Request Form

events.views.my.myorgs(request)[source]

List of associated organizations

events.views.my.mywo(request)[source]

List Events (if LNL member will list their events)

events.views.my.office_hours(request)[source]

Form for updating a user’s office hours (Officers only)

events.views.my.survey_success(request)[source]

Displayed to the user after successfully completing a survey

class events.views.orgs.OrgVerificationCreate(**kwargs)[source]

Verify that a client’s billing details are valid

form_class

alias of events.forms.IOrgVerificationForm

form_valid(form)[source]

If the form is valid, save the associated model.

get_form_kwargs()[source]

Return the keyword arguments for instantiating the form.

get_success_url()[source]

Return the URL to redirect to after processing a valid form.

model

alias of events.models.OrgBillingVerificationEvent

msg = 'Mark Client billing as valid'
perms = ('events.create_verifications',)
template_name = 'form_crispy_cbv.html'
events.views.orgs.addeditorgs(request, org_id=None)[source]

internal form for adding/editing an org Clients should not have access to this page. The accounts field autocomplete exposes ALL funds, and this form also allows the owner of the org to be changed without the email verification done by the org transfer form. Clients should use the much less confusing ‘orgedit’ view.

events.views.orgs.org_acceptxfer(request, idstr)[source]

Complete an organization transfer

events.views.orgs.org_mkxfer(request, id)[source]

Begin the process of transferring ownership of an organization

events.views.orgs.orgdetail(request, org_id)[source]

Organization detail page

events.views.orgs.orgedit(request, id)[source]

Form for editing organization details (client view)

events.views.orgs.vieworgs(request)[source]

Lists all organizations


Forms

class events.forms.AttachmentForm(event, externally_uploaded=False, *args, **kwargs)[source]
class Meta[source]
fields = ('for_service', 'attachment', 'note')
model

alias of events.models.EventAttachment

base_fields = {'attachment': <django.forms.fields.FileField object>, 'for_service': <django.forms.models.ModelMultipleChoiceField object>, 'note': <django.forms.fields.CharField object>}
declared_fields = {}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class events.forms.BillingEmailForm(billing, *args, **kwargs)[source]
class Meta[source]
fields = ('subject', 'message', 'email_to_users', 'email_to_orgs')
model

alias of events.models.BillingEmail

base_fields = {'email_to_orgs': <events.forms.CustomOrganizationEmailModelMultipleChoiceField object>, 'email_to_users': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'message': <django.forms.fields.CharField object>, 'subject': <django.forms.fields.CharField object>}
clean()[source]

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

declared_fields = {'email_to_orgs': <events.forms.CustomOrganizationEmailModelMultipleChoiceField object>, 'email_to_users': <ajax_select.fields.AutoCompleteSelectMultipleField object>}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class events.forms.BillingForm(event, *args, **kwargs)[source]
class Meta[source]
fields = ('date_billed', 'amount')
model

alias of events.models.Billing

base_fields = {'amount': <django.forms.fields.DecimalField object>, 'date_billed': <django.forms.fields.DateField object>}
declared_fields = {}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class events.forms.BillingUpdateForm(event, *args, **kwargs)[source]
class Meta[source]
fields = ('date_paid', 'amount')
model

alias of events.models.Billing

base_fields = {'amount': <django.forms.fields.DecimalField object>, 'date_paid': <django.forms.fields.DateField object>}
declared_fields = {}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class events.forms.BulkCheckinForm(*args, **kwargs)[source]
base_fields = {'id': <django.forms.fields.IntegerField object>}
declared_fields = {'id': <django.forms.fields.IntegerField object>}
media
secure_widget = <django.forms.widgets.PasswordInput object>
class events.forms.CCIForm(event, *args, **kwargs)[source]

Crew Chief Instance form

class Meta[source]
fields = ('category', 'crew_chief', 'service', 'setup_location', 'setup_start')
model

alias of events.models.EventCCInstance

base_fields = {'category': <django.forms.models.ModelChoiceField object>, 'crew_chief': <ajax_select.fields.AutoCompleteSelectField object>, 'service': <django.forms.models.ModelChoiceField object>, 'setup_location': <events.fields.GroupedModelChoiceField object>, 'setup_start': <django.forms.fields.SplitDateTimeField object>}
clean()[source]

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

declared_fields = {'category': <django.forms.models.ModelChoiceField object>, 'crew_chief': <ajax_select.fields.AutoCompleteSelectField object>, 'service': <django.forms.models.ModelChoiceField object>, 'setup_location': <events.fields.GroupedModelChoiceField object>, 'setup_start': <django.forms.fields.SplitDateTimeField object>}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class events.forms.CheckoutHoursForm(*args, **kwargs)[source]
base_fields = {'total': <django.forms.fields.DecimalField object>}
clean()[source]

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

declared_fields = {'total': <django.forms.fields.DecimalField object>}
disabled_widget = <django.forms.widgets.NumberInput object>
media
class events.forms.CrewAssign(*args, **kwargs)[source]
class Meta[source]
fields = ('crew',)
model

alias of events.models.Event

base_fields = {'crew': <ajax_select.fields.AutoCompleteSelectMultipleField object>}
declared_fields = {'crew': <ajax_select.fields.AutoCompleteSelectMultipleField object>}
media
class events.forms.CrewCheckinForm(*args, **kwargs)[source]
base_fields = {}
declared_fields = {}
media
class events.forms.CrewCheckoutForm(*args, **kwargs)[source]
base_fields = {'checkin': <django.forms.fields.SplitDateTimeField object>, 'checkout': <django.forms.fields.SplitDateTimeField object>}
clean()[source]

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

declared_fields = {'checkin': <django.forms.fields.SplitDateTimeField object>, 'checkout': <django.forms.fields.SplitDateTimeField object>}
media
class events.forms.CrewChiefAssign(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]
class Meta[source]
fields = ('crew_chief',)
model

alias of events.models.Event

base_fields = {'crew_chief': <ajax_select.fields.AutoCompleteSelectMultipleField object>}
declared_fields = {'crew_chief': <ajax_select.fields.AutoCompleteSelectMultipleField object>}
media
class events.forms.CustomAutoCompleteSelectMultipleField(channel, *args, **kwargs)[source]
has_changed(initial_value, data_value)[source]

Return True if data differs from initial.

class events.forms.CustomEventModelMultipleChoiceField(queryset, **kwargs)[source]
label_from_instance(event)[source]

Convert objects into strings and generate the labels for the choices presented by this object. Subclasses can override this method to customize the display of the choices.

class events.forms.CustomOrganizationEmailModelMultipleChoiceField(queryset, **kwargs)[source]
label_from_instance(org)[source]

Convert objects into strings and generate the labels for the choices presented by this object. Subclasses can override this method to customize the display of the choices.

class events.forms.EditHoursForm(*args, **kwargs)[source]
class Meta[source]
fields = ('hours',)
model

alias of events.models.Hours

base_fields = {'hours': <django.forms.fields.DecimalField object>}
declared_fields = {}
media
class events.forms.EventApprovalForm(*args, **kwargs)[source]
class Meta[source]
fields = ['description', 'internal_notes', 'datetime_start', 'datetime_end', 'org', 'billing_org', 'billed_in_bulk', 'datetime_setup_complete', 'lighting', 'lighting_reqs', 'sound', 'sound_reqs', 'projection', 'proj_reqs', 'otherservices', 'otherservice_reqs']
model

alias of events.models.Event

widgets = {'description': <pagedown.widgets.PagedownWidget object>, 'internal_notes': <class 'pagedown.widgets.PagedownWidget'>, 'lighting_reqs': <pagedown.widgets.PagedownWidget object>, 'otherservice_reqs': <pagedown.widgets.PagedownWidget object>, 'proj_reqs': <pagedown.widgets.PagedownWidget object>, 'sound_reqs': <pagedown.widgets.PagedownWidget object>}
base_fields = {'billed_in_bulk': <django.forms.fields.BooleanField object>, 'billing_org': <ajax_select.fields.AutoCompleteSelectField object>, 'datetime_end': <django.forms.fields.SplitDateTimeField object>, 'datetime_setup_complete': <django.forms.fields.SplitDateTimeField object>, 'datetime_start': <django.forms.fields.SplitDateTimeField object>, 'description': <django.forms.fields.CharField object>, 'internal_notes': <django.forms.fields.CharField object>, 'lighting': <django.forms.models.ModelChoiceField object>, 'lighting_reqs': <django.forms.fields.CharField object>, 'org': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'otherservice_reqs': <django.forms.fields.CharField object>, 'otherservices': <django.forms.models.ModelMultipleChoiceField object>, 'proj_reqs': <django.forms.fields.CharField object>, 'projection': <django.forms.models.ModelChoiceField object>, 'sound': <django.forms.models.ModelChoiceField object>, 'sound_reqs': <django.forms.fields.CharField object>}
declared_fields = {'billing_org': <ajax_select.fields.AutoCompleteSelectField object>, 'datetime_end': <django.forms.fields.SplitDateTimeField object>, 'datetime_setup_complete': <django.forms.fields.SplitDateTimeField object>, 'datetime_start': <django.forms.fields.SplitDateTimeField object>, 'org': <ajax_select.fields.AutoCompleteSelectMultipleField object>}
media
class events.forms.EventDenialForm(*args, **kwargs)[source]
class Meta[source]
fields = ['cancelled_reason', 'send_email']
model

alias of events.models.BaseEvent

widgets = {'cancelled_reason': <pagedown.widgets.PagedownWidget object>}
base_fields = {'cancelled_reason': <django.forms.fields.CharField object>, 'send_email': <django.forms.fields.BooleanField object>}
declared_fields = {'send_email': <django.forms.fields.BooleanField object>}
media
class events.forms.EventMeetingForm(*args, **kwargs)[source]
class Meta[source]
fields = ['datetime_setup_start', 'datetime_setup_complete', 'crew_chief', 'crew']
model

alias of events.models.Event

base_fields = {'crew': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'crew_chief': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'datetime_setup_complete': <django.forms.fields.SplitDateTimeField object>, 'datetime_setup_start': <django.forms.fields.SplitDateTimeField object>}
declared_fields = {'crew': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'crew_chief': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'datetime_setup_complete': <django.forms.fields.SplitDateTimeField object>, 'datetime_setup_start': <django.forms.fields.SplitDateTimeField object>}
media
class events.forms.EventReviewForm(*args, **kwargs)[source]
class Meta[source]
fields = ('org', 'billing_org', 'internal_notes')
model

alias of events.models.Event

widgets = {'internal_notes': <pagedown.widgets.PagedownWidget object>}
base_fields = {'billing_org': <ajax_select.fields.AutoCompleteSelectField object>, 'internal_notes': <django.forms.fields.CharField object>, 'org': <ajax_select.fields.AutoCompleteSelectMultipleField object>}
declared_fields = {'billing_org': <ajax_select.fields.AutoCompleteSelectField object>, 'org': <ajax_select.fields.AutoCompleteSelectMultipleField object>}
media
class events.forms.ExternalOrgUpdateForm(*args, **kwargs)[source]

Organization Details Form for Client

class Meta[source]
fields = ('exec_email', 'address', 'phone', 'associated_users', 'workday_fund', 'worktag')
model

alias of events.models.Organization

base_fields = {'address': <django.forms.fields.CharField object>, 'associated_users': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'exec_email': <django.forms.fields.EmailField object>, 'phone': <django.forms.fields.CharField object>, 'workday_fund': <django.forms.fields.TypedChoiceField object>, 'worktag': <django.forms.fields.CharField object>}
clean_worktag()[source]
declared_fields = {'associated_users': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'worktag': <django.forms.fields.CharField object>}
media
class events.forms.ExtraForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]
class Meta[source]
fields = ('extra', 'quant')
model

alias of events.models.ExtraInstance

base_fields = {'extra': <events.fields.GroupedModelChoiceField object>, 'quant': <django.forms.fields.IntegerField object>}
declared_fields = {'extra': <events.fields.GroupedModelChoiceField object>}
media
class events.forms.IOrgForm(request_user, *args, **kwargs)[source]

Internal Organization Details Form

class FieldAccess[source]
billing_edit = <data.forms.FieldAccessLevel object>
billing_view = <data.forms.FieldAccessLevel object>
everything_else_edit = <data.forms.FieldAccessLevel object>
internal_notes_edit = <data.forms.FieldAccessLevel object>
internal_notes_view = <data.forms.FieldAccessLevel object>
members_edit = <data.forms.FieldAccessLevel object>
members_view = <data.forms.FieldAccessLevel object>
owner_edit = <data.forms.FieldAccessLevel object>
class Meta[source]
fields = ('name', 'exec_email', 'address', 'phone', 'associated_orgs', 'personal', 'workday_fund', 'worktag', 'user_in_charge', 'associated_users', 'notes', 'delinquent')
model

alias of events.models.Organization

base_fields = {'address': <django.forms.fields.CharField object>, 'associated_orgs': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'associated_users': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'delinquent': <django.forms.fields.BooleanField object>, 'exec_email': <django.forms.fields.EmailField object>, 'name': <django.forms.fields.CharField object>, 'notes': <django.forms.fields.CharField object>, 'personal': <django.forms.fields.BooleanField object>, 'phone': <django.forms.fields.CharField object>, 'user_in_charge': <ajax_select.fields.AutoCompleteSelectField object>, 'workday_fund': <django.forms.fields.TypedChoiceField object>, 'worktag': <django.forms.fields.CharField object>}
clean_worktag()[source]
declared_fields = {'associated_orgs': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'associated_users': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'notes': <django.forms.fields.CharField object>, 'user_in_charge': <ajax_select.fields.AutoCompleteSelectField object>, 'worktag': <django.forms.fields.CharField object>}
media
class events.forms.IOrgVerificationForm(org, *args, **kwargs)[source]

Internal Client Billing Verification Form

class Meta[source]
fields = ('date', 'verified_by', 'note')
model

alias of events.models.OrgBillingVerificationEvent

base_fields = {'date': <django.forms.fields.DateField object>, 'note': <django.forms.fields.CharField object>, 'verified_by': <ajax_select.fields.AutoCompleteSelectField object>}
declared_fields = {'verified_by': <ajax_select.fields.AutoCompleteSelectField object>}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class events.forms.InternalEventForm(request_user, *args, **kwargs)[source]
class FieldAccess[source]
billing_edit = <data.forms.FieldAccessLevel object>
billing_view = <data.forms.FieldAccessLevel object>
change_flags = <data.forms.FieldAccessLevel object>
change_lnl_contact = <data.forms.FieldAccessLevel object>
change_owner = <data.forms.FieldAccessLevel object>
change_type = <data.forms.FieldAccessLevel object>
edit_descriptions = <data.forms.FieldAccessLevel object>
event_times = <data.forms.FieldAccessLevel object>
hide_internal_notes = <data.forms.FieldAccessLevel object>
internal_notes_write = <data.forms.FieldAccessLevel object>
class Meta[source]
fields = ('event_name', 'location', 'lnl_contact', 'description', 'internal_notes', 'billing_org', 'billed_in_bulk', 'contact', 'org', 'datetime_setup_complete', 'datetime_start', 'datetime_end', 'lighting', 'lighting_reqs', 'sound', 'sound_reqs', 'projection', 'proj_reqs', 'otherservices', 'otherservice_reqs', 'sensitive', 'test_event')
model

alias of events.models.Event

widgets = {'description': <pagedown.widgets.PagedownWidget object>, 'internal_notes': <class 'pagedown.widgets.PagedownWidget'>, 'lighting_reqs': <pagedown.widgets.PagedownWidget object>, 'otherservice_reqs': <pagedown.widgets.PagedownWidget object>, 'proj_reqs': <pagedown.widgets.PagedownWidget object>, 'sound_reqs': <pagedown.widgets.PagedownWidget object>}
base_fields = {'billed_in_bulk': <django.forms.fields.BooleanField object>, 'billing_org': <ajax_select.fields.AutoCompleteSelectField object>, 'contact': <ajax_select.fields.AutoCompleteSelectField object>, 'datetime_end': <django.forms.fields.SplitDateTimeField object>, 'datetime_setup_complete': <django.forms.fields.SplitDateTimeField object>, 'datetime_start': <django.forms.fields.SplitDateTimeField object>, 'description': <django.forms.fields.CharField object>, 'event_name': <django.forms.fields.CharField object>, 'internal_notes': <django.forms.fields.CharField object>, 'lighting': <django.forms.models.ModelChoiceField object>, 'lighting_reqs': <django.forms.fields.CharField object>, 'lnl_contact': <ajax_select.fields.AutoCompleteSelectField object>, 'location': <events.fields.GroupedModelChoiceField object>, 'org': <events.forms.CustomAutoCompleteSelectMultipleField object>, 'otherservice_reqs': <django.forms.fields.CharField object>, 'otherservices': <django.forms.models.ModelMultipleChoiceField object>, 'proj_reqs': <django.forms.fields.CharField object>, 'projection': <django.forms.models.ModelChoiceField object>, 'sensitive': <django.forms.fields.BooleanField object>, 'sound': <django.forms.models.ModelChoiceField object>, 'sound_reqs': <django.forms.fields.CharField object>, 'test_event': <django.forms.fields.BooleanField object>}
declared_fields = {'billing_org': <ajax_select.fields.AutoCompleteSelectField object>, 'contact': <ajax_select.fields.AutoCompleteSelectField object>, 'datetime_end': <django.forms.fields.SplitDateTimeField object>, 'datetime_setup_complete': <django.forms.fields.SplitDateTimeField object>, 'datetime_start': <django.forms.fields.SplitDateTimeField object>, 'lnl_contact': <ajax_select.fields.AutoCompleteSelectField object>, 'location': <events.fields.GroupedModelChoiceField object>, 'org': <events.forms.CustomAutoCompleteSelectMultipleField object>, 'otherservices': <django.forms.models.ModelMultipleChoiceField object>}
media
class events.forms.InternalEventForm2019(request_user, *args, **kwargs)[source]
class FieldAccess[source]
billing_edit = <data.forms.FieldAccessLevel object>
billing_view = <data.forms.FieldAccessLevel object>
cancelled_reason_edit = <data.forms.FieldAccessLevel object>
change_entered_into_workday = <data.forms.FieldAccessLevel object>
change_flags = <data.forms.FieldAccessLevel object>
change_lnl_contact = <data.forms.FieldAccessLevel object>
change_owner = <data.forms.FieldAccessLevel object>
change_type = <data.forms.FieldAccessLevel object>
edit_descriptions = <data.forms.FieldAccessLevel object>
event_times = <data.forms.FieldAccessLevel object>
hide_internal_notes = <data.forms.FieldAccessLevel object>
internal_notes_write = <data.forms.FieldAccessLevel object>
survey_edit = <data.forms.FieldAccessLevel object>
survey_view = <data.forms.FieldAccessLevel object>
class Meta[source]
fields = ('event_name', 'location', 'lnl_contact', 'description', 'internal_notes', 'billing_org', 'billed_in_bulk', 'contact', 'org', 'datetime_setup_complete', 'datetime_start', 'datetime_end', 'sensitive', 'test_event', 'entered_into_workday', 'send_survey', 'max_crew', 'cancelled_reason', 'reference_code')
model

alias of events.models.Event2019

widgets = {'cancelled_reason': <django.forms.widgets.TextInput object>, 'description': <pagedown.widgets.PagedownWidget object>, 'internal_notes': <pagedown.widgets.PagedownWidget object>}
base_fields = {'billed_in_bulk': <django.forms.fields.BooleanField object>, 'billing_org': <ajax_select.fields.AutoCompleteSelectField object>, 'cancelled_reason': <django.forms.fields.CharField object>, 'contact': <ajax_select.fields.AutoCompleteSelectField object>, 'datetime_end': <django.forms.fields.SplitDateTimeField object>, 'datetime_setup_complete': <django.forms.fields.SplitDateTimeField object>, 'datetime_start': <django.forms.fields.SplitDateTimeField object>, 'description': <django.forms.fields.CharField object>, 'entered_into_workday': <django.forms.fields.BooleanField object>, 'event_name': <django.forms.fields.CharField object>, 'internal_notes': <django.forms.fields.CharField object>, 'lnl_contact': <ajax_select.fields.AutoCompleteSelectField object>, 'location': <events.fields.GroupedModelChoiceField object>, 'max_crew': <django.forms.fields.IntegerField object>, 'org': <events.forms.CustomAutoCompleteSelectMultipleField object>, 'reference_code': <django.forms.fields.CharField object>, 'send_survey': <django.forms.fields.BooleanField object>, 'sensitive': <django.forms.fields.BooleanField object>, 'test_event': <django.forms.fields.BooleanField object>}
cancelled_reason = (<django.forms.fields.CharField object>,)
declared_fields = {'billing_org': <ajax_select.fields.AutoCompleteSelectField object>, 'contact': <ajax_select.fields.AutoCompleteSelectField object>, 'datetime_end': <django.forms.fields.SplitDateTimeField object>, 'datetime_setup_complete': <django.forms.fields.SplitDateTimeField object>, 'datetime_start': <django.forms.fields.SplitDateTimeField object>, 'lnl_contact': <ajax_select.fields.AutoCompleteSelectField object>, 'location': <events.fields.GroupedModelChoiceField object>, 'max_crew': <django.forms.fields.IntegerField object>, 'org': <events.forms.CustomAutoCompleteSelectMultipleField object>, 'reference_code': <django.forms.fields.CharField object>}
media
class events.forms.InternalReportForm(event, *args, **kwargs)[source]

Crew Chief Report Form

class FieldAccess[source]
admin = <data.forms.FieldAccessLevel object>
all = <data.forms.FieldAccessLevel object>
avg_user = <data.forms.FieldAccessLevel object>
class Meta[source]
fields = ('crew_chief', 'report')
model

alias of events.models.CCReport

widgets = {'report': <pagedown.widgets.PagedownWidget object>}
base_fields = {'crew_chief': <ajax_select.fields.AutoCompleteSelectField object>, 'report': <django.forms.fields.CharField object>}
declared_fields = {'crew_chief': <ajax_select.fields.AutoCompleteSelectField object>}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class events.forms.MKHoursForm(event, *args, **kwargs)[source]

Event Hours Form

class Meta[source]
fields = ('user', 'hours', 'category', 'service')
model

alias of events.models.Hours

base_fields = {'category': <django.forms.models.ModelChoiceField object>, 'hours': <django.forms.fields.DecimalField object>, 'service': <django.forms.models.ModelChoiceField object>, 'user': <ajax_select.fields.AutoCompleteSelectField object>}
clean()[source]

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

declared_fields = {'category': <django.forms.models.ModelChoiceField object>, 'hours': <django.forms.fields.DecimalField object>, 'service': <django.forms.models.ModelChoiceField object>, 'user': <ajax_select.fields.AutoCompleteSelectField object>}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class events.forms.MultiBillingEmailForm(multibilling, *args, **kwargs)[source]
class Meta[source]
fields = ('subject', 'message', 'email_to_users', 'email_to_orgs')
model

alias of events.models.MultiBillingEmail

base_fields = {'email_to_orgs': <events.forms.CustomOrganizationEmailModelMultipleChoiceField object>, 'email_to_users': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'message': <django.forms.fields.CharField object>, 'subject': <django.forms.fields.CharField object>}
clean()[source]

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

declared_fields = {'email_to_orgs': <events.forms.CustomOrganizationEmailModelMultipleChoiceField object>, 'email_to_users': <ajax_select.fields.AutoCompleteSelectMultipleField object>}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class events.forms.MultiBillingForm(*args, **kwargs)[source]
class Meta[source]
fields = ('events', 'date_billed', 'amount')
model

alias of events.models.MultiBilling

base_fields = {'amount': <django.forms.fields.DecimalField object>, 'date_billed': <django.forms.fields.DateField object>, 'events': <events.forms.CustomEventModelMultipleChoiceField object>}
clean()[source]

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

declared_fields = {'events': <events.forms.CustomEventModelMultipleChoiceField object>}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class events.forms.MultiBillingUpdateForm(*args, **kwargs)[source]
class Meta[source]
fields = ('date_paid', 'amount')
model

alias of events.models.MultiBilling

base_fields = {'amount': <django.forms.fields.DecimalField object>, 'date_paid': <django.forms.fields.DateField object>}
declared_fields = {}
media
class events.forms.OfficeHoursForm(*args, **kwargs)[source]
class Meta[source]
fields = ('day', 'location', 'hour_start', 'hour_end')
model

alias of events.models.OfficeHour

base_fields = {'day': <django.forms.fields.TypedChoiceField object>, 'hour_end': <django.forms.fields.TimeField object>, 'hour_start': <django.forms.fields.TimeField object>, 'location': <django.forms.models.ModelChoiceField object>}
declared_fields = {}
media
class events.forms.OrgXFerForm(org, user, *args, **kwargs)[source]

Organization Transfer Form

class Meta[source]
fields = ('new_user_in_charge',)
model

alias of events.models.OrganizationTransfer

base_fields = {'new_user_in_charge': <django.forms.models.ModelChoiceField object>}
declared_fields = {}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class events.forms.PostEventSurveyForm(event, *args, **kwargs)[source]
class Meta[source]
fields = ('services_quality', 'lighting_quality', 'sound_quality', 'work_order_method', 'work_order_experience', 'work_order_ease', 'work_order_comments', 'communication_responsiveness', 'pricelist_ux', 'setup_on_time', 'crew_respectfulness', 'price_appropriate', 'customer_would_return', 'comments')
model

alias of events.models.PostEventSurvey

base_fields = {'comments': <django.forms.fields.CharField object>, 'communication_responsiveness': <django.forms.fields.ChoiceField object>, 'crew_respectfulness': <django.forms.fields.ChoiceField object>, 'customer_would_return': <django.forms.fields.ChoiceField object>, 'lighting_quality': <django.forms.fields.ChoiceField object>, 'price_appropriate': <django.forms.fields.ChoiceField object>, 'pricelist_ux': <django.forms.fields.ChoiceField object>, 'services_quality': <django.forms.fields.ChoiceField object>, 'setup_on_time': <django.forms.fields.ChoiceField object>, 'sound_quality': <django.forms.fields.ChoiceField object>, 'work_order_comments': <django.forms.fields.CharField object>, 'work_order_ease': <django.forms.fields.ChoiceField object>, 'work_order_experience': <django.forms.fields.ChoiceField object>, 'work_order_method': <django.forms.fields.ChoiceField object>}
declared_fields = {'communication_responsiveness': <django.forms.fields.ChoiceField object>, 'crew_respectfulness': <django.forms.fields.ChoiceField object>, 'customer_would_return': <django.forms.fields.ChoiceField object>, 'lighting_quality': <django.forms.fields.ChoiceField object>, 'price_appropriate': <django.forms.fields.ChoiceField object>, 'pricelist_ux': <django.forms.fields.ChoiceField object>, 'services_quality': <django.forms.fields.ChoiceField object>, 'setup_on_time': <django.forms.fields.ChoiceField object>, 'sound_quality': <django.forms.fields.ChoiceField object>, 'work_order_ease': <django.forms.fields.ChoiceField object>, 'work_order_experience': <django.forms.fields.ChoiceField object>, 'work_order_method': <django.forms.fields.ChoiceField object>}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class events.forms.SelfServiceOrgRequestForm(*args, **kwargs)[source]
base_fields = {'address': <django.forms.fields.CharField object>, 'client_name': <django.forms.fields.CharField object>, 'email': <django.forms.fields.EmailField object>, 'phone': <django.forms.fields.CharField object>}
declared_fields = {'address': <django.forms.fields.CharField object>, 'client_name': <django.forms.fields.CharField object>, 'email': <django.forms.fields.EmailField object>, 'phone': <django.forms.fields.CharField object>}
media
class events.forms.ServiceInstanceForm(event, *args, **kwargs)[source]
class Meta[source]
fields = ('service', 'detail')
model

alias of events.models.ServiceInstance

widgets = {'detail': <pagedown.widgets.PagedownWidget object>}
base_fields = {'detail': <django.forms.fields.CharField object>, 'service': <django.forms.models.ModelChoiceField object>}
declared_fields = {'service': <django.forms.models.ModelChoiceField object>}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class events.forms.SurveyCustomRadioSelect(attrs=None, choices=())[source]
input_type = 'radio'
media
option_template_name = 'survey_custom_radio_select.html'
template_name = 'survey_custom_radio_select.html'
class events.forms.WorkdayForm(*args, **kwargs)[source]

Workday Bill Pay Form

class Meta[source]
fields = ('workday_fund', 'worktag', 'workday_form_comments')
model

alias of events.models.Event2019

base_fields = {'workday_form_comments': <django.forms.fields.CharField object>, 'workday_fund': <django.forms.fields.TypedChoiceField object>, 'worktag': <django.forms.fields.CharField object>}
clean_worktag()[source]
declared_fields = {'worktag': <django.forms.fields.CharField object>}
media
class events.forms.WorkorderRepeatForm(*args, **kwargs)[source]
class Meta[source]
fields = ['location', 'event_name', 'description', 'datetime_start', 'datetime_end', 'datetime_setup_complete', 'lighting', 'lighting_reqs', 'sound', 'sound_reqs', 'projection', 'proj_reqs', 'otherservices', 'otherservice_reqs']
model

alias of events.models.Event

base_fields = {'datetime_end': <django.forms.fields.SplitDateTimeField object>, 'datetime_setup_complete': <django.forms.fields.SplitDateTimeField object>, 'datetime_start': <django.forms.fields.SplitDateTimeField object>, 'description': <django.forms.fields.CharField object>, 'event_name': <django.forms.fields.CharField object>, 'lighting': <django.forms.models.ModelChoiceField object>, 'lighting_reqs': <django.forms.fields.CharField object>, 'location': <events.fields.GroupedModelChoiceField object>, 'otherservice_reqs': <django.forms.fields.CharField object>, 'otherservices': <django.forms.models.ModelMultipleChoiceField object>, 'proj_reqs': <django.forms.fields.CharField object>, 'projection': <django.forms.models.ModelChoiceField object>, 'sound': <django.forms.models.ModelChoiceField object>, 'sound_reqs': <django.forms.fields.CharField object>}
clean()[source]

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

declared_fields = {'datetime_end': <django.forms.fields.SplitDateTimeField object>, 'datetime_setup_complete': <django.forms.fields.SplitDateTimeField object>, 'datetime_start': <django.forms.fields.SplitDateTimeField object>, 'lighting': <django.forms.models.ModelChoiceField object>, 'location': <events.fields.GroupedModelChoiceField object>, 'otherservices': <django.forms.models.ModelMultipleChoiceField object>, 'projection': <django.forms.models.ModelChoiceField object>, 'sound': <django.forms.models.ModelChoiceField object>}
media
class events.forms.WorkorderSubmit(*args, **kwargs)[source]
class Meta[source]
exclude = ('submitted_by', 'submitted_ip', 'approved', 'crew', 'crew_chief', 'report', 'closed', 'payment_amount', 'paid')
model

alias of events.models.Event

base_fields = {'approved_by': <django.forms.models.ModelChoiceField object>, 'approved_on': <django.forms.fields.DateTimeField object>, 'billed_in_bulk': <django.forms.fields.BooleanField object>, 'billing_org': <django.forms.models.ModelChoiceField object>, 'cancelled': <django.forms.fields.BooleanField object>, 'cancelled_by': <django.forms.models.ModelChoiceField object>, 'cancelled_on': <django.forms.fields.DateTimeField object>, 'cancelled_reason': <django.forms.fields.CharField object>, 'ccs_needed': <django.forms.fields.IntegerField object>, 'closed_by': <django.forms.models.ModelChoiceField object>, 'closed_on': <django.forms.fields.DateTimeField object>, 'contact': <django.forms.models.ModelChoiceField object>, 'datetime_end': <django.forms.fields.DateTimeField object>, 'datetime_setup_complete': <django.forms.fields.DateTimeField object>, 'datetime_setup_start': <django.forms.fields.DateTimeField object>, 'datetime_start': <django.forms.fields.DateTimeField object>, 'description': <django.forms.fields.CharField object>, 'event_name': <django.forms.fields.CharField object>, 'internal_notes': <django.forms.fields.CharField object>, 'lighting': <django.forms.models.ModelChoiceField object>, 'lighting_reqs': <django.forms.fields.CharField object>, 'lnl_contact': <django.forms.models.ModelChoiceField object>, 'location': <django.forms.models.ModelChoiceField object>, 'org': <django.forms.models.ModelMultipleChoiceField object>, 'otherservice_reqs': <django.forms.fields.CharField object>, 'otherservices': <django.forms.models.ModelMultipleChoiceField object>, 'proj_reqs': <django.forms.fields.CharField object>, 'projection': <django.forms.models.ModelChoiceField object>, 'reviewed': <django.forms.fields.BooleanField object>, 'reviewed_by': <django.forms.models.ModelChoiceField object>, 'reviewed_on': <django.forms.fields.DateTimeField object>, 'sensitive': <django.forms.fields.BooleanField object>, 'setup_location': <django.forms.models.ModelChoiceField object>, 'sound': <django.forms.models.ModelChoiceField object>, 'sound_reqs': <django.forms.fields.CharField object>, 'test_event': <django.forms.fields.BooleanField object>}
declared_fields = {}
media
class events.forms.WorkshopDatesForm(*args, **kwargs)[source]
class Meta[source]
fields = ('workshop', 'date')
model

alias of events.models.WorkshopDate

base_fields = {'date': <django.forms.fields.SplitDateTimeField object>, 'workshop': <django.forms.models.ModelChoiceField object>}
declared_fields = {'date': <django.forms.fields.SplitDateTimeField object>}
media
class events.forms.WorkshopForm(*args, **kwargs)[source]
class Meta[source]
fields = ('name', 'instructors', 'description', 'location', 'notes')
model

alias of events.models.Workshop

base_fields = {'description': <django.forms.fields.CharField object>, 'instructors': <django.forms.fields.CharField object>, 'location': <django.forms.fields.CharField object>, 'name': <django.forms.fields.CharField object>, 'notes': <django.forms.fields.CharField object>}
declared_fields = {}
media
events.forms.get_qs_from_event(event)[source]

Inventory

This module provides tools to help users view and manage LNL’s equipment inventory.

Models

class inventory.models.EquipmentCategory(id, name, usual_place, parent)[source]
Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – Name (required)
  • usual_place (ForeignKey to Location) – Default place for items of this category. Inherits from parent categories.
  • parent (TreeForeignKey to EquipmentCategory) – If this is a subcategory, the parent is what this is a subcategory of. Choose ‘—’ if not.
  • lft (PositiveIntegerField) – Lft (required)
  • rght (PositiveIntegerField) – Rght (required)
  • tree_id (PositiveIntegerField) – Tree id (required)
  • level (PositiveIntegerField) – Level (required)
exception DoesNotExist
exception MultipleObjectsReturned
breadcrumbs
children

Reverse Manager for inventory.EquipmentCategory’s parent

default_location
equipmentclass_set

Reverse Manager for inventory.EquipmentClass’s category

get_ancestors_inclusive
get_descendants_inclusive
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

level

PositiveIntegerField(editable=False)

lft

PositiveIntegerField(editable=False)

name

CharField(max_length=64)

parent

TreeForeignKey(blank=True, null=True, help_text=”If this is a subcategory, the parent is what this is a subcategory of. Choose ‘—’ if not.”, related_name=”children”, on_delete=CASCADE(), to= EquipmentCategory)

Parent: If this is a subcategory, the parent is what this is a subcategory of. Choose ‘—’ if not.

parent_id

Raw (integer) FK for parent

classmethod possible_locations()[source]
rght

PositiveIntegerField(editable=False)

tree_id

PositiveIntegerField(db_index=True, editable=False)

usual_place

ForeignKey(blank=True, null=True, help_text=”Default place for items of this category. Inherits from parent categories.”, on_delete=PROTECT(), to= Location)

Usual place: Default place for items of this category. Inherits from parent categories.

usual_place_id

Raw (integer) FK for usual_place

class inventory.models.EquipmentClass(id, name, category, description, value, model_number, manufacturer, url, holds_items, length, width, height, weight, wiki_text)[source]
Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – Name (required)
  • category (TreeForeignKey to EquipmentCategory) – Category (required)
  • description (TextField) – Function, appearance, and included acessories
  • value (DecimalField) – Estimated purchase value
  • model_number (CharField) – Model number
  • manufacturer (CharField) – Manufacturer
  • url (URLField) – Url
  • holds_items (BooleanField) – Can hold other items (default=False)
  • length (DecimalField) – Length in inches
  • width (DecimalField) – Width in inches
  • height (DecimalField) – Height in inches
  • weight (DecimalField) – Weight in lbs.
  • wiki_text (TextField) – How to use this item
exception DoesNotExist
exception MultipleObjectsReturned
breadcrumbs
category

TreeForeignKey(on_delete=CASCADE(), to= EquipmentCategory)

category_id

Raw (integer) FK for category

description

TextField(blank=True, null=True, help_text=”Function, appearance, and included acessories”)

Description: Function, appearance, and included acessories

height

DecimalField(blank=True, null=True, help_text=”Height in inches”, max_digits=6, decimal_places=2)

Height: Height in inches

holds_items

BooleanField(default=False, help_text=”Can hold other items”)

Holds items: Can hold other items

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

items

Reverse Manager for inventory.EquipmentItem’s item_type

length

DecimalField(blank=True, null=True, help_text=”Length in inches”, max_digits=6, decimal_places=2)

Length: Length in inches

manufacturer

CharField(max_length=128, blank=True, null=True)

model_number

CharField(max_length=190, blank=True, null=True)

name

CharField(max_length=190)

objects = <django.db.models.manager.Manager object>
size()[source]
url

CharField(blank=True, null=True)

value

DecimalField(blank=True, null=True, help_text=”Estimated purchase value”, max_digits=9, decimal_places=2)

Value: Estimated purchase value

weight

DecimalField(blank=True, null=True, help_text=”Weight in lbs.”, max_digits=6, decimal_places=2)

Weight: Weight in lbs.

width

DecimalField(blank=True, null=True, help_text=”Width in inches”, max_digits=6, decimal_places=2)

Width: Width in inches

wiki_text

TextField(blank=True, null=True, help_text=”How to use this item”)

Wiki text: How to use this item

class inventory.models.EquipmentItem(id, item_type, serial_number, case, barcode, purchase_date, home, features)[source]
Parameters:
  • id (AutoField) – Id (required)
  • item_type (ForeignKey to EquipmentClass) – Item type (required)
  • serial_number (CharField) – Serial number
  • case (TreeForeignKey to EquipmentItem) – Case or item that contains this item
  • barcode (BigIntegerField) – Barcode
  • purchase_date (DateField) – Purchase date (required)
  • home (ForeignKey to Location) – Place where this item typically resides.
  • features (CharField) – Identifying features
  • lft (PositiveIntegerField) – Lft (required)
  • rght (PositiveIntegerField) – Rght (required)
  • tree_id (PositiveIntegerField) – Tree id (required)
  • level (PositiveIntegerField) – Level (required)
exception DoesNotExist
exception MultipleObjectsReturned
barcode

BigIntegerField(unique=True, blank=True, null=True)

breadcrumbs
case

TreeForeignKey(blank=True, null=True, help_text=”Case or item that contains this item”, related_name=”contents”, on_delete=CASCADE(), to= EquipmentItem)

Case: Case or item that contains this item

case_id

Raw (integer) FK for case

contents

Reverse Manager for inventory.EquipmentItem’s case

features

CharField(verbose_name=”Identifying Features”, max_length=128, blank=True, null=True)

get_next_by_purchase_date(*, field=<django.db.models.fields.DateField: purchase_date>, is_next=True, **kwargs)
get_previous_by_purchase_date(*, field=<django.db.models.fields.DateField: purchase_date>, is_next=False, **kwargs)
home

ForeignKey(blank=True, null=True, help_text=”Place where this item typically resides.”, on_delete=PROTECT(), to= Location)

Home: Place where this item typically resides.

home_id

Raw (integer) FK for home

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

item_type

ForeignKey(related_name=”items”, on_delete=CASCADE(), to= EquipmentClass)

item_type_id

Raw (integer) FK for item_type

level

PositiveIntegerField(editable=False)

lft

PositiveIntegerField(editable=False)

location
maintenance

Reverse Manager for inventory.EquipmentMaintEntry’s equipment

objects = <inventory.models.EquipmentItemManager object>
purchase_date

DateField(blank=True)

rght

PositiveIntegerField(editable=False)

save(*args, **kwargs)[source]

If this is a new node, sets tree fields up before it is inserted into the database, making room in the tree structure as neccessary, defaulting to making the new node the last child of its parent.

It the node’s left and right edge indicators already been set, we take this as indication that the node has already been set up for insertion, so its tree fields are left untouched.

If this is an existing node and its parent has been changed, performs reparenting in the tree structure, defaulting to making the node the last child of its new parent.

In either case, if the node’s class has its order_insertion_by tree option set, the node will be inserted or moved to the appropriate position to maintain ordering by the specified field.

serial_number

CharField(max_length=190, blank=True, null=True)

status
tree_id

PositiveIntegerField(db_index=True, editable=False)

unsafe_to_delete
class inventory.models.EquipmentItemManager[source]
bulk_add_helper(item_type, num_to_add, put_into=None)[source]
class inventory.models.EquipmentMaintEntry(id, date, user, title, entry, equipment, status)[source]
Parameters:
  • id (AutoField) – Id (required)
  • date (DateTimeField) – Date (required)
  • user (ForeignKey to User) – User (required)
  • title (CharField) – Title (required)
  • entry (TextField) – Entry
  • equipment (ForeignKey to EquipmentItem) – Equipment (required)
  • status (ForeignKey to EquipmentStatus) – Status (required)
exception DoesNotExist
exception MultipleObjectsReturned
date

DateTimeField(auto_now_add=True)

entry

TextField(blank=True, null=True)

equipment

ForeignKey(related_name=”maintenance”, on_delete=CASCADE(), to= EquipmentItem)

equipment_id

Raw (integer) FK for equipment

get_next_by_date(*, field=<django.db.models.fields.DateTimeField: date>, is_next=True, **kwargs)
get_previous_by_date(*, field=<django.db.models.fields.DateTimeField: date>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
status

ForeignKey(on_delete=PROTECT(), to= EquipmentStatus)

status_id

Raw (integer) FK for status

title

CharField(max_length=32)

user

ForeignKey(on_delete=PROTECT(), to= User)

user_id

Raw (integer) FK for user

class inventory.models.EquipmentStatus(id, name, glyphicon)[source]
Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – Name (required)
  • glyphicon (CharField) – Glyphicon (required)
exception DoesNotExist
exception MultipleObjectsReturned
equipmentmaintentry_set

Reverse Manager for inventory.EquipmentMaintEntry’s status

glyphicon

CharField(max_length=32)

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

name

CharField(max_length=32)

objects = <django.db.models.manager.Manager object>

Views

inventory.views.cat(request, category_id)[source]

List items by category

Parameters:category_id – The primary key value of the equipment category
inventory.views.generate_receipt(request, data, renter, checkin=False)[source]

Generate a checkin or checkout receipt

Parameters:
  • data – List of dictionaries containing the metadata for each of the items that were just checked in or out
  • renter – The name of the user or organization the items were rented to
  • checkin – Set to True if generating a receipt for checkin
Returns:

Itemized list of item details and the total rental price

inventory.views.item_detail(request, item_id)[source]

Detail page for a specific item

inventory.views.old_snipe_checkin(request)[source]

Equipment inventory checkin form. Communicates with Snipe via their API.

inventory.views.old_snipe_checkout(request)[source]

Equipment inventory checkout form. Communicates with Snipe via their API.

inventory.views.remove_saved_tag(post_data, tag)[source]

Removes an item from the list of pending assets and/or accessories stored in a Snipe Checkin or Checkout form.

Parameters:
  • post_data – The request’s POST data
  • tag – The asset tag value of the item to remove
Returns:

The updated form data and list of item metadata dictionaries

inventory.views.retrieve_saved_tags(post_data)[source]

Converts the asset tag data stored in a form into a list of dictionaries.

Parameters:post_data – The request’s POST data
Returns:A list of dictionaries containing the metadata for the selected assets and/or accessories
inventory.views.snipe_checkin(request)[source]

Equipment inventory checkin form. Communicates with Snipe via their API.

inventory.views.snipe_checkout(request)[source]

Equipment inventory checkout form. Communicates with the Snipe API.

inventory.views.snipe_credentials(request)[source]

Display the login credentials for the general Snipe account

inventory.views.type_detail(request, type_id)[source]

Detail page for a group of items

inventory.views.update_tag_list(post_data, new_item)[source]

Adds a new item to the list of asset tags stored in hidden fields on the Snipe Checkin and Checkout forms and returns an additional dictionary containing basic information for each verified item.

Parameters:
  • post_data – The request’s POST data
  • new_item – The next asset or accessory to add to the list
Returns:

Updated form data and basic inventory item information (Dictionary and list of Dictionaries)

inventory.views.view_all(request)[source]

Lists all items in LNL’s inventory (no longer maintained - read-only)


Forms

class inventory.forms.SnipeCheckinForm(checkin_from_choices, *args, **kwargs)[source]
base_fields = {'asset_tags': <django.forms.fields.CharField object>}
declared_fields = {'asset_tags': <django.forms.fields.CharField object>}
media
class inventory.forms.SnipeCheckoutForm(checkout_to_choices, *args, **kwargs)[source]
base_fields = {'asset_tags': <django.forms.fields.CharField object>}
declared_fields = {'asset_tags': <django.forms.fields.CharField object>}
media
class inventory.forms.SnipeRentalForm(rental_clients, checkout, *args, **kwargs)[source]
base_fields = {'asset_tag': <django.forms.fields.CharField object>, 'saved_tags': <django.forms.fields.CharField object>}
declared_fields = {'asset_tag': <django.forms.fields.CharField object>, 'saved_tags': <django.forms.fields.CharField object>}
media

API Methods

inventory.api.api_request(method, endpoint, data=None)[source]

Send an API request to Snipe

Parameters:
  • methodGET, POST, PUT, PATCH or DELETE
  • endpoint – Snipe endpoint (Must start with / - i.e. /users or /accessories/1)
  • data – JSON data (if applicable)
Returns:

Response

inventory.api.checkedout(tag)[source]

Determine which users a specific accessory has been checked out to

Parameters:tag – The item’s asset tag number (String)
Returns:List of active rentals for the specified item(s)
inventory.api.checkin(identifier, accessory=False)[source]

Check in an asset or accessory from a user

Parameters:
  • identifier – For accessories, use the ID of the accessory+user relationship. For assets, use its Snipe ID.
  • accessory – Must be true if the item is an accessory
Returns:

API Response

inventory.api.checkout(item_id, renter_id, accessory=False)[source]

Check an asset or accessory out to a user

Parameters:
  • item_id – The item’s Snipe ID number
  • renter_id – The Snipe ID number for the user checking out the item
  • accessory – Must be True if the item is an accessory
Returns:

API Response

inventory.api.get_item_info(tag)[source]

Retrieve information about an item in LNL’s inventory (supports both assets and accessories)

Parameters:tag – The item’s asset tag number (String)
Returns:Dictionary - Item details
inventory.api.load_rental_clients()[source]

Retrieves a list of users in the rental group (rental clients).

Returns:List of rental clients

Meetings

This module is used to manage information related to LNL meetings.

Models

class meetings.models.AnnounceSend(*args, **kwargs)[source]

Log of when a meeting notice has been sent out

Parameters:
  • id (AutoField) – Id (required)
  • announce (ForeignKey to MeetingAnnounce) – Announce (required)
  • sent_at (DateTimeField) – Sent at (required)
  • sent_success (BooleanField) – Sent success (default=False)
exception DoesNotExist
exception MultipleObjectsReturned
announce

ForeignKey(on_delete=CASCADE(), to= MeetingAnnounce)

announce_id

Raw (integer) FK for announce

get_next_by_sent_at(*, field=<django.db.models.fields.DateTimeField: sent_at>, is_next=True, **kwargs)
get_previous_by_sent_at(*, field=<django.db.models.fields.DateTimeField: sent_at>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
sent_at

DateTimeField(auto_now_add=True)

sent_success

BooleanField(default=False)

class meetings.models.CCNoticeSend(*args, **kwargs)[source]

Contents of an email containing a meeting CC notice

Parameters:
  • id (AutoField) – Id (required)
  • meeting (ForeignKey to Meeting) – Meeting (required)
  • sent_at (DateTimeField) – Sent at (required)
  • sent_success (BooleanField) – Sent success (default=False)
  • uuid (UUIDField) – Uuid (default=<function uuid4 at 0x7f60a490c680>)
  • email_to (ForeignKey to TargetEmailList) – Email to (default=<function get_default_email at 0x7f60a2bc1e60>)
  • addtl_message (TextField) – Additional message
  • events (ManyToManyField to BaseEvent) – Events (required)
exception DoesNotExist
exception MultipleObjectsReturned
addtl_message

TextField(verbose_name=”Additional Message”, blank=True, null=True)

email_to

ForeignKey(default=get_default_email(), on_delete=PROTECT(), to= TargetEmailList)

email_to_id

Raw (integer) FK for email_to

events

Reverse Manager for meetings.CCNoticeSend’s events

get_next_by_sent_at(*, field=<django.db.models.fields.DateTimeField: sent_at>, is_next=True, **kwargs)
get_previous_by_sent_at(*, field=<django.db.models.fields.DateTimeField: sent_at>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

meeting

ForeignKey(related_name=”meetingccnotices”, on_delete=CASCADE(), to= Meeting)

meeting_id

Raw (integer) FK for meeting

objects = <django.db.models.manager.Manager object>
reverse_ordered_events
sent_at

DateTimeField(auto_now_add=True)

sent_success

BooleanField(default=False)

subject
uuid

UUIDField(blank=True, default=uuid4(), editable=False)

class meetings.models.Meeting(id, datetime, duration, meeting_type, location, agenda, minutes, minutes_private)[source]
Parameters:
  • id (AutoField) – Id (required)
  • datetime (DateTimeField) – Start time (required)
  • duration (DurationField) – Duration (default=1:00:00)
  • meeting_type (ForeignKey to MeetingType) – Meeting type (default=1)
  • location (ForeignKey to Location) – Location
  • agenda (TextField) – Agenda
  • minutes (TextField) – Minutes
  • minutes_private (TextField) – Closed minutes
  • attendance (ManyToManyField to User) – Attendance (required)
exception DoesNotExist
exception MultipleObjectsReturned
agenda

TextField(blank=True, null=True)

attachments

Reverse Manager for meetings.MtgAttachment’s meeting

attendance

Reverse Manager for meetings.Meeting’s attendance

cal_desc()[source]

No description will be provided for meetings displayed on calendars

cal_end()[source]

The meeting end time used by calendars

cal_guid()[source]

Unique event id used by calendars

Link to be displayed on calendars

cal_location()[source]

The location name used by calendars

cal_name()[source]

Title to display on calendars

cal_start()[source]

The meeting start time used by calendars

datetime

DateTimeField(verbose_name=”Start Time”)

duration

DurationField(default=1:00:00)

endtime
get_absolute_url()[source]
get_next_by_datetime(*, field=<django.db.models.fields.DateTimeField: datetime>, is_next=True, **kwargs)
get_previous_by_datetime(*, field=<django.db.models.fields.DateTimeField: datetime>, is_next=False, **kwargs)
glyphicon = 'briefcase'
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

location

ForeignKey(blank=True, null=True, on_delete=PROTECT(), to= Location)

location_id

Raw (integer) FK for location

meeting_type

ForeignKey(default=1, on_delete=PROTECT(), to= MeetingType)

meeting_type_id

Raw (integer) FK for meeting_type

meetingannounce_set

Reverse Manager for meetings.MeetingAnnounce’s meeting

meetingccnotices

Reverse Manager for meetings.CCNoticeSend’s meeting

minutes

TextField(blank=True, null=True)

minutes_private

TextField(verbose_name=”Closed Minutes”, blank=True, null=True)

name
objects = <django.db.models.manager.Manager object>
class meetings.models.MeetingAnnounce(*args, **kwargs)[source]

Contents of an email containing a meeting notice

Parameters:
  • id (AutoField) – Id (required)
  • meeting (ForeignKey to Meeting) – Meeting (required)
  • subject (CharField) – Subject (required)
  • message (TextField) – Message (required)
  • email_to (ForeignKey to TargetEmailList) – Email to (required)
  • added (DateTimeField) – Added (required)
  • uuid (UUIDField) – Uuid (default=<function uuid4 at 0x7f60a490c680>)
  • events (ManyToManyField to BaseEvent) – Events (required)
exception DoesNotExist
exception MultipleObjectsReturned
added

DateTimeField(auto_now_add=True)

announcesend_set

Reverse Manager for meetings.AnnounceSend’s announce

email_to

ForeignKey(on_delete=PROTECT(), to= TargetEmailList)

email_to_id

Raw (integer) FK for email_to

events

Reverse Manager for meetings.MeetingAnnounce’s events

get_next_by_added(*, field=<django.db.models.fields.DateTimeField: added>, is_next=True, **kwargs)
get_previous_by_added(*, field=<django.db.models.fields.DateTimeField: added>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

meeting

ForeignKey(on_delete=CASCADE(), to= Meeting)

meeting_id

Raw (integer) FK for meeting

message

TextField()

objects = <django.db.models.manager.Manager object>
reverse_ordered_events
subject

CharField(max_length=128)

uuid

UUIDField(blank=True, default=uuid4(), editable=False)

class meetings.models.MeetingType(*args, **kwargs)[source]

Used to specify the type of meeting (i.e. Exec Board, General Body, etc.)

Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – Name (required)
  • archived (BooleanField) – Archived (default=False)
exception DoesNotExist
exception MultipleObjectsReturned
archived

BooleanField(default=False)

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

invite_subscriptions

Reverse Manager for accounts.UserPreferences’s meeting_invite_subscriptions

meeting_set

Reverse Manager for meetings.Meeting’s meeting_type

name

CharField(max_length=32)

objects = <django.db.models.manager.Manager object>
class meetings.models.MtgAttachment(id, created, modified, name, file, author, meeting, private)[source]
Parameters:
  • id (AutoField) – Id (required)
  • created (CreationDateTimeField) – Created (required)
  • modified (ModificationDateTimeField) – Modified (required)
  • name (CharField) – Name (required)
  • file (FileField) – File (required)
  • author (ForeignKey to User) – Author (required)
  • meeting (ForeignKey to Meeting) – Meeting
  • private (BooleanField) – Private (default=False)
exception DoesNotExist
exception MultipleObjectsReturned
author

ForeignKey(editable=False, on_delete=PROTECT(), to= User)

author_id

Raw (integer) FK for author

file

The descriptor for the file attribute on the model instance. Return a FieldFile when accessed so you can write code like:

>>> from myapp.models import MyModel
>>> instance = MyModel.objects.get(pk=1)
>>> instance.file.size

Assign a file object on assignment so you can do:

>>> with open('/path/to/hello.world') as f:
...     instance.file = File(f)
get_next_by_created(*, field=<django_extensions.db.fields.CreationDateTimeField: created>, is_next=True, **kwargs)
get_next_by_modified(*, field=<django_extensions.db.fields.ModificationDateTimeField: modified>, is_next=True, **kwargs)
get_previous_by_created(*, field=<django_extensions.db.fields.CreationDateTimeField: created>, is_next=False, **kwargs)
get_previous_by_modified(*, field=<django_extensions.db.fields.ModificationDateTimeField: modified>, is_next=False, **kwargs)
glyphicon = 'paperclip'
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

meeting

ForeignKey(null=True, related_name=”attachments”, on_delete=CASCADE(), to= Meeting)

meeting_id

Raw (integer) FK for meeting

name

CharField(max_length=64)

objects = <django.db.models.manager.Manager object>
private

BooleanField(default=False)

class meetings.models.TargetEmailList(*args, **kwargs)[source]

Represents a target email address (i.e. aliases)

Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – Name (required)
  • email (EmailField) – Email (required)
exception DoesNotExist
exception MultipleObjectsReturned
ccnoticesend_set

Reverse Manager for meetings.CCNoticeSend’s email_to

email

CharField(max_length=254)

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

meetingannounce_set

Reverse Manager for meetings.MeetingAnnounce’s email_to

name

CharField(max_length=16)

objects = <django.db.models.manager.Manager object>
meetings.models.get_default_email()[source]
meetings.models.mtg_attachment_file_name(instance, filename)[source]

Views

class meetings.views.DeleteMeeting(**kwargs)[source]

Delete a meeting

delete(request, *args, **kwargs)[source]

Call the delete() method on the fetched object and then redirect to the success URL.

get_success_url()[source]
model

alias of meetings.models.Meeting

msg = 'Delete Meeting'
perms = 'meetings.edit_mtg'
pk_url_kwarg = 'mtg_id'
template_name = 'form_delete_cbv.html'
meetings.views.download_att(request, mtg_id, att_id)[source]

Download a meeting attachment

Parameters:
  • mtg_id – The primary key value of the meeting
  • att_id – The primary key value of the attachment
meetings.views.download_invite(request, mtg_id)[source]

Generate and download an ics file

meetings.views.editattendance(request, mtg_id)[source]

Update event details

meetings.views.listattendance(request, page=1)[source]

List all meetings

meetings.views.mkccnotice(request, mtg_id)[source]

Send a CC meeting notice

meetings.views.mknotice(request, mtg_id)[source]

Send a meeting notice

meetings.views.modify_att(request, mtg_id, att_id)[source]

Update an attachment

Parameters:
  • mtg_id – The primary key value of the meeting
  • att_id – The primary key value of the attachment
meetings.views.newattendance(request)[source]

Create a new meeting

meetings.views.rm_att(request, mtg_id, att_id)[source]

Remove an attachment from a meeting

Parameters:
  • mtg_id – The primary key value of the meeting
  • att_id – The primary key value of the attachment
meetings.views.send_invite(meeting, is_update=False, is_cancellation=False)[source]

Generate and send an interactive calendar invite for a meeting (separate from a meeting notice).

Parameters:
  • meeting – The meeting to include in the invite
  • is_update – Set to True if the meeting details have just been updated
  • is_cancellation – Set to True if the meeting has been cancelled
meetings.views.updateevent(request, mtg_id, event_id)[source]

Update crew chief assignments for an event

Parameters:
  • mtg_id – The primary key value of the meeting (redirects to meeting detail page)
  • event_id – The primary key value of the event (pre-2019 events only)
meetings.views.viewattendance(request, mtg_id)[source]

View event details


Forms

class meetings.forms.AnnounceCCSendForm(meeting, *args, **kwargs)[source]
class Meta[source]
fields = ('events', 'addtl_message', 'email_to')
model

alias of meetings.models.CCNoticeSend

widgets = {'addtl_message': <pagedown.widgets.PagedownWidget object>}
base_fields = {'addtl_message': <django.forms.fields.CharField object>, 'email_to': <django.forms.models.ModelChoiceField object>, 'events': <django.forms.models.ModelMultipleChoiceField object>}
declared_fields = {}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class meetings.forms.AnnounceSendForm(meeting, *args, **kwargs)[source]
class Meta[source]
fields = ('events', 'subject', 'message', 'email_to')
model

alias of meetings.models.MeetingAnnounce

widgets = {'message': <pagedown.widgets.PagedownWidget object>}
base_fields = {'email_to': <django.forms.models.ModelChoiceField object>, 'events': <django.forms.models.ModelMultipleChoiceField object>, 'message': <django.forms.fields.CharField object>, 'subject': <django.forms.fields.CharField object>}
declared_fields = {'events': <django.forms.models.ModelMultipleChoiceField object>}
media
save(commit=True)[source]

Save this form’s self.instance object if commit=True. Otherwise, add a save_m2m() method to the form which can be called after the instance is saved manually at a later time. Return the model instance.

class meetings.forms.MeetingAdditionForm(*args, **kwargs)[source]
class FieldAccess[source]
edit_closed = <data.forms.FieldAccessLevel object>
hasperm = <data.forms.FieldAccessLevel object>
no_closed = <data.forms.FieldAccessLevel object>
class Meta[source]
fields = ('meeting_type', 'location', 'datetime', 'attendance', 'duration', 'agenda', 'minutes', 'minutes_private')
model

alias of meetings.models.Meeting

widgets = {'datetime': <django.forms.widgets.DateInput object>}
base_fields = {'agenda': <django.forms.fields.CharField object>, 'attachments': <multiupload.fields.MultiFileField object>, 'attachments_private': <multiupload.fields.MultiFileField object>, 'attendance': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'datetime': <django.forms.fields.SplitDateTimeField object>, 'duration': <natural_duration.fields.NaturalDurationField object>, 'location': <django.forms.models.ModelChoiceField object>, 'meeting_type': <django.forms.models.ModelChoiceField object>, 'minutes': <django.forms.fields.CharField object>, 'minutes_private': <django.forms.fields.CharField object>}
declared_fields = {'agenda': <django.forms.fields.CharField object>, 'attachments': <multiupload.fields.MultiFileField object>, 'attachments_private': <multiupload.fields.MultiFileField object>, 'attendance': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'datetime': <django.forms.fields.SplitDateTimeField object>, 'duration': <natural_duration.fields.NaturalDurationField object>, 'location': <django.forms.models.ModelChoiceField object>, 'meeting_type': <django.forms.models.ModelChoiceField object>, 'minutes': <django.forms.fields.CharField object>, 'minutes_private': <django.forms.fields.CharField object>}
media
class meetings.forms.MtgAttachmentEditForm(*args, **kwargs)[source]
class Meta[source]
fields = ('name', 'file', 'private')
model

alias of meetings.models.MtgAttachment

base_fields = {'file': <django.forms.fields.FileField object>, 'name': <django.forms.fields.CharField object>, 'private': <django.forms.fields.BooleanField object>}
declared_fields = {}
media

Members

This module maintains member training data.

Models

class members.models.Trainee(*args, **kwargs)[source]

Record of an individual’s completion or revocation of training

Parameters:
  • id (AutoField) – Id (required)
  • training (ForeignKey to Training) – Training (required)
  • person (ForeignKey to User) – Person (required)
  • revoked (BooleanField) – Revoked (default=False)
  • revoked_by (ForeignKey to User) – Revoked by
  • revoked_on (DateTimeField) – Revoked on
  • notes (TextField) – Notes (required)
  • _order (OrderWrt) – order (required)
exception DoesNotExist
exception MultipleObjectsReturned
get_next_in_order(*, is_next=True)
get_previous_in_order(*, is_next=False)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

is_valid()[source]
notes

TextField(blank=True)

objects = <django.db.models.manager.Manager object>
person

ForeignKey(related_name=”trainings”, on_delete=PROTECT(), to= User)

person_id

Raw (integer) FK for person

revoked

BooleanField(default=False)

revoked_by

ForeignKey(blank=True, null=True, related_name=”trainings_revoked”, on_delete=PROTECT(), to= User)

revoked_by_id

Raw (integer) FK for revoked_by

revoked_on

DateTimeField(blank=True, null=True)

training

ForeignKey(related_name=”trainees”, on_delete=CASCADE(), to= Training)

training_id

Raw (integer) FK for training

was_valid_on(date)[source]
class members.models.Training(*args, **kwargs)[source]

A training event

Parameters:
  • id (AutoField) – Id (required)
  • training_type (ForeignKey to TrainingType) – Training type (required)
  • date (DateField) – Date (required)
  • trainer (ForeignKey to User) – Trainer
  • recorded_by (ForeignKey to User) – Recorded by (required)
  • recorded_on (DateTimeField) – Recorded on (required)
  • expiration_date (DateField) – Expiration date
  • notes (TextField) – Notes (required)
exception DoesNotExist
exception MultipleObjectsReturned
date

DateField()

expiration_date

DateField(blank=True, null=True)

get_next_by_date(*, field=<django.db.models.fields.DateField: date>, is_next=True, **kwargs)
get_next_by_recorded_on(*, field=<django.db.models.fields.DateTimeField: recorded_on>, is_next=True, **kwargs)
get_previous_by_date(*, field=<django.db.models.fields.DateField: date>, is_next=False, **kwargs)
get_previous_by_recorded_on(*, field=<django.db.models.fields.DateTimeField: recorded_on>, is_next=False, **kwargs)
get_trainee_order()
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

is_expired()[source]
notes

TextField(blank=True)

objects = <django.db.models.manager.Manager object>
recorded_by

ForeignKey(editable=False, related_name=”trainings_entered”, on_delete=PROTECT(), to= User)

recorded_by_id

Raw (integer) FK for recorded_by

recorded_on

DateTimeField(auto_now_add=True)

set_trainee_order(id_list, using=None)
trainees

Reverse Manager for members.Trainee’s training

trainer

ForeignKey(blank=True, null=True, related_name=”trainings_run”, on_delete=PROTECT(), to= User)

trainer_id

Raw (integer) FK for trainer

training_type

ForeignKey(related_name=”trainings”, on_delete=PROTECT(), to= TrainingType)

training_type_id

Raw (integer) FK for training_type

class members.models.TrainingType(id, name, external, description)[source]
Parameters:
  • id (AutoField) – Id (required)
  • name (CharField) – Name (required)
  • external (BooleanField) – External (default=False)
  • description (TextField) – Description (required)
exception DoesNotExist
exception MultipleObjectsReturned
description

TextField()

external

BooleanField(default=False)

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

name

CharField(max_length=64, unique=True)

objects = <django.db.models.manager.Manager object>
trainings

Reverse Manager for members.Training’s training_type


Views

members.views.enter_training(request)[source]

Update training records

members.views.revoke_training(request, pk)[source]

Revoke training for a particular user

members.views.trainee_notes(request, pk)[source]

Update trainee records for a particular individual (must not be expired)

members.views.training_list(request)[source]

List all members with valid training


Forms

class members.forms.TraineeNotesForm(*args, **kwargs)[source]
class Meta[source]
fields = ('notes',)
model

alias of members.models.Trainee

base_fields = {'notes': <django.forms.fields.CharField object>}
declared_fields = {}
media
class members.forms.TrainingForm(*args, **kwargs)[source]
base_fields = {'date': <django.forms.fields.DateField object>, 'expiration_date': <django.forms.fields.DateField object>, 'notes': <django.forms.fields.CharField object>, 'trainees': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'trainer': <ajax_select.fields.AutoCompleteSelectField object>, 'training_type': <django.forms.models.ModelChoiceField object>}
clean()[source]

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

clean_trainees()[source]
clean_trainer()[source]
declared_fields = {'date': <django.forms.fields.DateField object>, 'expiration_date': <django.forms.fields.DateField object>, 'notes': <django.forms.fields.CharField object>, 'trainees': <ajax_select.fields.AutoCompleteSelectMultipleField object>, 'trainer': <ajax_select.fields.AutoCompleteSelectField object>, 'training_type': <django.forms.models.ModelChoiceField object>}
media

Pages

This module makes it possible to quickly create new webpages using the Django admin site. You can create custom pages which utilize our static site’s stylesheets as well as simple onboarding screens which can be displayed immediately after a user logs in. This is also where you’ll find the source code for our main onboarding processes for new members.

Models

class pages.models.CarouselImg(*args, **kwargs)[source]

Image to be displayed as part of a carousel on a custom page

Parameters:
  • id (AutoField) – Id (required)
  • internal_name (CharField) – Internal name (required)
  • img (ImageField) – Img (required)
  • href (ForeignKey to Page) – Href
  • caption_title (CharField) – Caption title
  • caption_desc (CharField) – Caption desc
exception DoesNotExist
exception MultipleObjectsReturned
caption_desc

CharField(max_length=128, blank=True, null=True)

caption_title

CharField(max_length=64, blank=True, null=True)

href

ForeignKey(blank=True, null=True, on_delete=SET_NULL(), to= Page)

href_id

Raw (integer) FK for href

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

img

Just like the FileDescriptor, but for ImageFields. The only difference is assigning the width/height to the width_field/height_field, if appropriate.

internal_name

CharField(max_length=64)

objects = <django.db.models.manager.Manager object>
page_set

Reverse Manager for pages.Page’s imgs

class pages.models.OnboardingRecord(*args, **kwargs)[source]

Log of onboarding pages that have been displayed to a user

Parameters:
  • id (AutoField) – Id (required)
  • user (ForeignKey to User) – User (required)
  • screens (ManyToManyField to OnboardingScreen) – Screens (required)
exception DoesNotExist
exception MultipleObjectsReturned
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
screens

Reverse Manager for pages.OnboardingRecord’s screens

user

ForeignKey(on_delete=CASCADE(), to= User)

user_id

Raw (integer) FK for user

class pages.models.OnboardingScreen(*args, **kwargs)[source]

Custom page to display to users after they log in. Can be assigned to individual users or groups.

Parameters:
  • id (AutoField) – Id (required)
  • title (CharField) – Title (required)
  • slug (SlugField) – Slug (required)
  • icon (CharField) – Icon or image HTML
  • content (TextField) – Content (required)
  • inverted (BooleanField) – Dark theme (default=False)
  • action_title (CharField) – If left blank this button will not be displayed
  • action_href (URLField) – URL to go to when clicked. If not supplied button will not be displayed.
  • action_color (CharField) – Action button - color
  • new_window (BooleanField) – Action button - open in new window (default=False)
  • next_btn (CharField) – Defaults to “Next”
  • users (ManyToManyField to User) – Select users to display this to (required)
  • groups (ManyToManyField to Group) – Select groups of users to display this to. (required)
exception DoesNotExist
exception MultipleObjectsReturned
action_color

CharField(verbose_name=”Action Button - Color”, max_length=16, blank=True, null=True)

action_href

CharField(verbose_name=”Action Button - href”, max_length=128, blank=True, null=True, help_text=”URL to go to when clicked. If not supplied button will not be displayed.”)

Action button - href: URL to go to when clicked. If not supplied button will not be displayed.

action_title

CharField(verbose_name=”Action Button - Text”, max_length=32, blank=True, null=True, help_text=”If left blank this button will not be displayed”)

Action button - text: If left blank this button will not be displayed

content

TextField()

groups

Reverse Manager for pages.OnboardingScreen’s groups

icon

CharField(max_length=300, blank=True, null=True, help_text=”Icon or image HTML”)

Icon: Icon or image HTML

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

inverted

BooleanField(verbose_name=”Dark Theme”, default=False)

new_window

BooleanField(verbose_name=”Action Button - Open in New Window”, default=False)

next_btn

CharField(verbose_name=”Next Button - Text”, max_length=32, blank=True, null=True, help_text=”Defaults to “Next””)

Next button - text: Defaults to “Next”

objects = <django.db.models.manager.Manager object>
records

Reverse Manager for pages.OnboardingRecord’s screens

slug

SlugField(max_length=64)

title

CharField(max_length=64)

users

Reverse Manager for pages.OnboardingScreen’s users

class pages.models.Page(*args, **kwargs)[source]

Custom dynamic page using the static site stylesheets

Parameters:
  • id (AutoField) – Id (required)
  • title (CharField) – Title (required)
  • slug (SlugField) – Slug (required)
  • description (TextField) – This page description may appear in search engine results and along with any links to this page. (required)
  • body (TextField) – Accepts raw text and/or HTML input (required)
  • body_in_jumbo (BooleanField) – Body in jumbo (default=False)
  • noindex (BooleanField) – Hide from search engines (default=False)
  • sitemap (BooleanField) – Include in sitemap (default=False)
  • sitemap_category (CharField) – Sitemap category
  • css (TextField) – Css (required)
  • imgs (ManyToManyField to CarouselImg) – Imgs (required)
exception DoesNotExist
exception MultipleObjectsReturned
body

TextField(help_text=”Accepts raw text and/or HTML input”)

Body: Accepts raw text and/or HTML input

body_in_jumbo

BooleanField(default=False)

carouselimg_set

Reverse Manager for pages.CarouselImg’s href

css

TextField(verbose_name=”CSS”, blank=True)

description

TextField(blank=True, help_text=”This page description may appear in search engine results and along with any links to this page.”)

Description: This page description may appear in search engine results and along with any links to this page.

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

imgs

Reverse Manager for pages.Page’s imgs

noindex

BooleanField(verbose_name=”Hide from search engines”, default=False)

objects = <django.db.models.manager.Manager object>
sitemap

BooleanField(verbose_name=”Include in Sitemap”, default=False)

sitemap_category

CharField(max_length=32, blank=True, null=True)

slug

SlugField(max_length=64)

title

CharField(max_length=64)


Views

class pages.views.OnboardingWizard(**kwargs)[source]

Onboarding wizard which helps guide new LNL members through setting up their accounts

done(form_list, **kwargs)[source]

This method must be overridden by a subclass to process to form data after processing all steps.

form_list = [<class 'pages.forms.OnboardingUserInfoForm'>, <class 'pages.forms.OnboardingContactInfoForm'>]
get_form_initial(step)[source]

Returns a dictionary which will be passed to the form for step as initial. If no initial data was provided while initializing the form wizard, an empty dictionary will be returned.

get_form_instance(step)[source]

Returns an object which will be passed to the form for step as instance. If no instance object was provided while initializing the form wizard, None will be returned.

get_form_kwargs(step=None)[source]

Returns the keyword arguments for instantiating the form (or formset) on the given step.

process_step(form)[source]

This method is used to postprocess the form data. By default, it returns the raw form.data dictionary.

template_name = 'onboarding.html'
pages.views.new_member_welcome(request)[source]

Welcome message for new members that kicks off the onboarding process

pages.views.onboarding_screen(request, slug)[source]

Generate and display an onboarding screen

pages.views.page(request, slug)[source]

Generate custom page

pages.views.recruitment_page(request)[source]

Serve LNL’s join page with list of upcoming or ongoing events


Forms

class pages.forms.OnboardingContactInfoForm(has_address, *args, **kwargs)[source]
class Meta[source]
layout = [('Text', '<h4 class="ui dividing header">Contact Information</h4>'), ('Text', '<div class="field"><label>Address / Office Location</label>'), ('Two Fields', ('Field', 'address'), ('Field', 'line_2')), ('Two Fields', ('Field', 'city'), ('Field', 'state')), ('Text', '</div>'), ('Field', 'phone'), ('Text', '<br>'), ('Text', '<div class="field"><label>Consent to receive text messages from LNL</label>'), ('Text', '<p style="color: black">LNL may periodically send you SMS text messages containing information about your business with us. This method of communication will never be used for marketing purposes and you may opt out at any time.</p></div>'), ('Field', 'sms'), ('Field', 'carrier'), ('Text', '<p style="color: darkgrey; padding-top: 2%; padding-bottom: 1%">By clicking next you agree to our <a href=\'https://lnl.wpi.edu/legal/privacy/\' target=\'_blank\'>Privacy Policy</a></p>')]
base_fields = {'address': <django.forms.fields.CharField object>, 'carrier': <django.forms.fields.ChoiceField object>, 'city': <django.forms.fields.CharField object>, 'line_2': <django.forms.fields.CharField object>, 'phone': <django.forms.fields.CharField object>, 'sms': <django.forms.fields.ChoiceField object>, 'state': <django.forms.fields.CharField object>}
clean_carrier()[source]
clean_phone()[source]
declared_fields = {'address': <django.forms.fields.CharField object>, 'carrier': <django.forms.fields.ChoiceField object>, 'city': <django.forms.fields.CharField object>, 'line_2': <django.forms.fields.CharField object>, 'phone': <django.forms.fields.CharField object>, 'sms': <django.forms.fields.ChoiceField object>, 'state': <django.forms.fields.CharField object>}
media
save()[source]
class pages.forms.OnboardingUserInfoForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]
class Meta[source]
fields = ('first_name', 'last_name', 'nickname', 'email', 'class_year', 'student_id', 'wpibox')
layout = [('Text', '<h4 class="ui dividing header">Personal Information</h4>'), ('Text', '<div class="field"><label>Name <span style="color: red">*</span></label>'), ('Two Fields', ('Field', 'first_name'), ('Field', 'last_name')), ('Text', '</div>'), ('Field', 'nickname'), ('Field', 'email'), ('Text', '<br><h4 class="ui dividing header">Student Information</h4>'), ('Field', 'class_year'), ('Two Fields', ('Text', '<div class="field"><label>Student ID</label>'), ('Field', 'student_id'), ('Text', '</div><div class="field"><label>WPI Box Number</label>'), ('Field', 'wpibox'), ('Text', '</div>'))]
model

alias of accounts.models.User

base_fields = {'class_year': <django.forms.fields.CharField object>, 'email': <django.forms.fields.EmailField object>, 'first_name': <django.forms.fields.CharField object>, 'last_name': <django.forms.fields.CharField object>, 'nickname': <django.forms.fields.CharField object>, 'student_id': <django.forms.fields.CharField object>, 'wpibox': <django.forms.fields.IntegerField object>}
clean_student_id()[source]
declared_fields = {'class_year': <django.forms.fields.CharField object>, 'email': <django.forms.fields.EmailField object>, 'first_name': <django.forms.fields.CharField object>, 'last_name': <django.forms.fields.CharField object>, 'nickname': <django.forms.fields.CharField object>, 'student_id': <django.forms.fields.CharField object>, 'wpibox': <django.forms.fields.IntegerField object>}
media
class pages.forms.SMSVerificationForm(user, *args, **kwargs)[source]
class Meta[source]
layout = [('Text', '<br><h4 class="ui dividing header">SMS Verification</h4>'), ('Text', '<p>A verification code was just sent to your phone. Check your messages and enter the 6-digit code below.</p>'), ('Field', 'code'), ('Text', "<div class='ui tiny message'>Didn't get your code? It may take a few minutes, so be patient. If after a few minutes you still haven't received your code, make sure you've entered your phone number correctly then try again.</div>")]
base_fields = {'code': <django.forms.fields.CharField object>}
clean_code()[source]
declared_fields = {'code': <django.forms.fields.CharField object>}
media
save()[source]
class pages.forms.SUIRadio(attrs=None, choices=())[source]
media
option_template_name = 'semantic_ui/semantic-option.html'
template_name = 'semantic_ui/semantic-radio.html'

PDFs

This module handles generating PDF files.

Views

pdfs.views.currency(dollars)[source]
pdfs.views.generate_event_bill_pdf(request, event)[source]
pdfs.views.generate_event_bill_pdf_multi(request, ids=None)[source]

Generate event bill PDF for multiple events (combine into one document)

pdfs.views.generate_event_bill_pdf_standalone(event, request=None)[source]

Generate event bill PDF without HttpResponse

Returns:PDF file
pdfs.views.generate_event_pdf(request, id)[source]
pdfs.views.generate_event_pdf_multi(request, ids=None)[source]

Generate workorder PDF for multiple events (combine into one document)

pdfs.views.generate_multibill_pdf(request, multibilling)[source]
pdfs.views.generate_multibill_pdf_standalone(multibilling, request=None)[source]

Generate multibill PDF without HttpResponse

Returns:PDF file
pdfs.views.generate_pdf(context, template, request)[source]
pdfs.views.generate_pdfs_standalone(ids=None)[source]

Generate PDF file without HttpResponse

Returns:PDF file
pdfs.views.generate_projection_pdf(request)[source]
pdfs.views.get_category_data(event)[source]

Parse event for service category information

Parameters:event – The event to parse
Returns:A dictionary
pdfs.views.get_extras(event)[source]
pdfs.views.get_multibill_data(multibilling)[source]

Convert HTML URIs to absolute system paths so xhtml2pdf can access those resources

Projection

This module handles most of the tasks related to projection.

Models

class projection.models.PITLevel(*args, **kwargs)[source]

Projectionist In Training (PIT) levels

Parameters:
  • id (AutoField) – Id (required)
  • name_short (CharField) – Name short (required)
  • name_long (CharField) – Name long (required)
  • ordering (IntegerField) – Ordering (default=0)
exception DoesNotExist
exception MultipleObjectsReturned
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

name_long

CharField(max_length=16)

name_short

CharField(max_length=3)

objects = <django.db.models.manager.Manager object>
ordering

IntegerField(default=0)

pitinstances

Reverse Manager for projection.PitInstance’s pit_level

pitrequest

Reverse Manager for projection.PitRequest’s level

class projection.models.PitInstance(*args, **kwargs)[source]

Record of a projectionist’s completion of a PIT

Parameters:
  • id (AutoField) – Id (required)
  • projectionist (ForeignKey to Projectionist) – Projectionist (required)
  • pit_level (ForeignKey to PITLevel) – Pit level (required)
  • created_on (DateField) – Created on (required)
  • valid (BooleanField) – Valid (default=True)
exception DoesNotExist
exception MultipleObjectsReturned
created_on

DateField()

get_next_by_created_on(*, field=<django.db.models.fields.DateField: created_on>, is_next=True, **kwargs)
get_previous_by_created_on(*, field=<django.db.models.fields.DateField: created_on>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
pit_level

ForeignKey(related_name=”pitinstances”, on_delete=PROTECT(), to= PITLevel)

pit_level_id

Raw (integer) FK for pit_level

projectionist

ForeignKey(related_name=”pitinstances”, on_delete=CASCADE(), to= Projectionist)

projectionist_id

Raw (integer) FK for projectionist

valid

BooleanField(default=True)

class projection.models.PitRequest(*args, **kwargs)[source]

Members can submit a request to receive their next level of training

Parameters:
  • id (AutoField) – Id (required)
  • projectionist (ForeignKey to Projectionist) – Projectionist (required)
  • level (ForeignKey to PITLevel) – Level (required)
  • requested_on (DateTimeField) – Requested on (required)
  • approved (BooleanField) – Approved (default=False)
  • scheduled_for (DateTimeField) – Scheduled for
exception DoesNotExist
exception MultipleObjectsReturned
approved

BooleanField(default=False)

get_next_by_requested_on(*, field=<django.db.models.fields.DateTimeField: requested_on>, is_next=True, **kwargs)
get_previous_by_requested_on(*, field=<django.db.models.fields.DateTimeField: requested_on>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

level

ForeignKey(related_name=”pitrequest”, on_delete=PROTECT(), to= PITLevel)

level_id

Raw (integer) FK for level

objects = <django.db.models.manager.Manager object>
projectionist

ForeignKey(related_name=”pitrequest”, on_delete=CASCADE(), to= Projectionist)

projectionist_id

Raw (integer) FK for projectionist

requested_on

DateTimeField(auto_now_add=True)

scheduled_for

DateTimeField(blank=True, null=True)

class projection.models.Projectionist(id, user, license_number, license_expiry)[source]
Parameters:
  • id (AutoField) – Id (required)
  • user (OneToOneField to User) – User (required)
  • license_number (CharField) – License number
  • license_expiry (DateField) – License expiry
exception DoesNotExist
exception MultipleObjectsReturned
expired
expiring
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

is_alumni
level
license_expiry

DateField(blank=True, null=True)

license_number

CharField(max_length=10, blank=True, null=True)

objects = <django.db.models.manager.Manager object>
pitinstances

Reverse Manager for projection.PitInstance’s projectionist

pitrequest

Reverse Manager for projection.PitRequest’s projectionist

user

OneToOneField(on_delete=CASCADE(), to= User)

user_id

Raw (integer) FK for user

validlevels

Views

class projection.views.BulkUpdateView(**kwargs)[source]

Update a PIT for multiple projectionists at the same time

form_class

alias of projection.forms.BulkUpdateForm

form_valid(form)[source]

If the form is valid, redirect to the supplied URL.

msg = 'Bulk Update Projectionists'
perms = 'projection.edit_pits'
success_url
template_name = 'form_crispy_cbv.html'
class projection.views.CancelPITRequest(**kwargs)[source]

Cancel a PIT request

get_success_url()[source]
model

alias of projection.models.PitRequest

msg = 'Cancelled PIT Request'
perms = 'projection.view_pits'
template_name = 'form_cancel_request.html'
class projection.views.PITRequest(**kwargs)[source]

Create a new PIT request

form_class

alias of projection.forms.PITRequestForm

form_valid(form)[source]

If the form is valid, redirect to the supplied URL.

get_context_data(**kwargs)[source]

Insert the form into the context dict.

model

alias of projection.models.PitRequest

perms = 'projection.view_pits'
template_name = 'projection_pit_request.html'
class projection.views.ProjectionCreate(**kwargs)[source]

Add a new projectionist

form_class

alias of projection.forms.ProjectionistForm

get_context_data(**kwargs)[source]

Insert the form into the context dict.

model

alias of projection.models.Projectionist

msg = 'Add Projectionist'
perms = 'projection.edit_pits'
success_url
template_name = 'form_crispy_projection.html'
class projection.views.ProjectionistDelete(**kwargs)[source]

Remove a projectionist (does not remove the associated user)

get_success_url()[source]
model

alias of projection.models.Projectionist

msg = 'Delete Projectionist'
perms = 'projection.edit_pits'
template_name = 'form_delete_cbv.html'
projection.views.bulk_projection(request)[source]

Add new projection events in bulk. This is an internal form and is often used when there are multiple showings over the course of a weekend.

projection.views.get_saturdays_for_range(date_1, date_2)[source]

Get a list of Saturdays in a given time frame

Parameters:
  • date_1 – Datetime of the lower bound
  • date_2 – Datetime of the upper bound
Returns:

An array of datetime objects

projection.views.manage_pit_request(request, id)[source]

Edit or approve a PIT request (not accessible by trainee)

projection.views.pit_complete(request, id)[source]

Mark a PIT as complete

projection.views.pit_request_update(request, id)[source]

Edit a PIT request (accessible by trainee)

projection.views.pit_schedule(request)[source]

List all PIT requests

projection.views.plist(request)[source]

List all projectionists

projection.views.plist_detail(request)[source]

Grid view of projectionists and their completed PITs

projection.views.projection_update(request, id)[source]

Update a projectionist’s license and / or PIT records

projection.views.send_request_notification(form, update=False)[source]

Send the head projectionist a PIT request notification


Forms

class projection.forms.BulkCreateForm(*args, **kwargs)[source]
base_fields = {'billing': <ajax_select.fields.AutoCompleteSelectField object>, 'contact': <ajax_select.fields.AutoCompleteSelectField object>, 'date_first': <django.forms.fields.DateField object>, 'date_second': <django.forms.fields.DateField object>}
declared_fields = {'billing': <ajax_select.fields.AutoCompleteSelectField object>, 'contact': <ajax_select.fields.AutoCompleteSelectField object>, 'date_first': <django.forms.fields.DateField object>, 'date_second': <django.forms.fields.DateField object>}
media
class projection.forms.BulkUpdateForm(*args, **kwargs)[source]
base_fields = {'date': <django.forms.fields.DateField object>, 'pit_level': <django.forms.models.ModelChoiceField object>, 'users': <ajax_select.fields.AutoCompleteSelectMultipleField object>}
create_updates()[source]
declared_fields = {'date': <django.forms.fields.DateField object>, 'pit_level': <django.forms.models.ModelChoiceField object>, 'users': <ajax_select.fields.AutoCompleteSelectMultipleField object>}
media
class projection.forms.DateEntryFormSetBase(*args, **kwargs)[source]
base_fields = {'date': <django.forms.fields.DateField object>, 'friday': <django.forms.fields.BooleanField object>, 'matinee': <django.forms.fields.BooleanField object>, 'name': <django.forms.fields.CharField object>, 'saturday': <django.forms.fields.BooleanField object>, 'sunday': <django.forms.fields.BooleanField object>}
declared_fields = {'date': <django.forms.fields.DateField object>, 'friday': <django.forms.fields.BooleanField object>, 'matinee': <django.forms.fields.BooleanField object>, 'name': <django.forms.fields.CharField object>, 'saturday': <django.forms.fields.BooleanField object>, 'sunday': <django.forms.fields.BooleanField object>}
media
save_objects(user, contact, org, ip=None)[source]
time_offsets = {'friday': datetime.timedelta(days=-1), 'matinee': datetime.timedelta(days=-1, seconds=64800), 'saturday': datetime.timedelta(0), 'sunday': datetime.timedelta(days=1)}
class projection.forms.InstanceForm(*args, **kwargs)[source]
class Meta[source]
fields = ('pit_level', 'created_on', 'valid')
model

alias of projection.models.PitInstance

base_fields = {'created_on': <django.forms.fields.DateField object>, 'pit_level': <django.forms.models.ModelChoiceField object>, 'valid': <django.forms.fields.BooleanField object>}
declared_fields = {'created_on': <django.forms.fields.DateField object>}
media
class projection.forms.PITRequestAdminForm(*args, **kwargs)[source]
base_fields = {'approved': <django.forms.fields.BooleanField object>, 'level': <django.forms.models.ModelChoiceField object>, 'scheduled_for': <django.forms.fields.SplitDateTimeField object>}
declared_fields = {'approved': <django.forms.fields.BooleanField object>, 'level': <django.forms.models.ModelChoiceField object>, 'scheduled_for': <django.forms.fields.SplitDateTimeField object>}
media
class projection.forms.PITRequestForm(*args, **kwargs)[source]
class Meta[source]
fields = ('level', 'scheduled_for', 'approved')
model

alias of projection.models.PitRequest

base_fields = {'approved': <django.forms.fields.BooleanField object>, 'level': <django.forms.models.ModelChoiceField object>, 'scheduled_for': <django.forms.fields.SplitDateTimeField object>}
declared_fields = {'level': <django.forms.models.ModelChoiceField object>, 'scheduled_for': <django.forms.fields.SplitDateTimeField object>}
media
class projection.forms.ProjectionistForm(*args, **kwargs)[source]
class Meta[source]
fields = ('user', 'license_number', 'license_expiry')
model

alias of projection.models.Projectionist

base_fields = {'license_expiry': <django.forms.fields.DateField object>, 'license_number': <django.forms.fields.CharField object>, 'user': <ajax_select.fields.AutoCompleteSelectField object>}
declared_fields = {'user': <ajax_select.fields.AutoCompleteSelectField object>}
media
class projection.forms.ProjectionistUpdateForm(*args, **kwargs)[source]
class Meta[source]
fields = ('license_number', 'license_expiry')
model

alias of projection.models.Projectionist

base_fields = {'license_expiry': <django.forms.fields.DateField object>, 'license_number': <django.forms.fields.CharField object>}
declared_fields = {}
media

RT

This module leverages RT’s REST API to create new interfaces for LNL’s ticketing system.

API Methods

rt.api.api_request(method, endpoint, data=None, token=None)[source]

Send an API request to the RT server

Parameters:
  • methodGET, POST, PUT, or DELETE
  • endpoint – RT endpoint
  • data – JSON data (if applicable)
  • token – RT Auth Token (uses the General account token if None)
Returns:

Response

rt.api.create_ticket(queue, reporter, subject, content, html=False, cc=None, attachments=None)[source]

Create a new ticket in RT

Parameters:
  • queue – The ticket queue to send the ticket to
  • reporter – Email address of the user submitting the ticket
  • subject – Brief subject line for quick reference
  • content – The contents of the ticket
  • html – If true, will set ContentType to text/html instead of text/plain
  • cc – List of additional email addresses to include in the ticket [Optional]
  • attachments – A list of attachments to include [Optional]
Returns:

API response

rt.api.fetch_ticket(ticket_id)[source]

Retrieve a ticket from RT

Parameters:ticket_id – The ticket’s ID #
Returns:Dictionary of ticket information
rt.api.get_user(username, token)[source]

Obtain user profile from RT

Parameters:
  • username – Username to use in search
  • token – Valid auth token with the proper permissions
Returns:

User profile (JSON) or None if not found

rt.api.permission_error(response)[source]

Check if a request to RT was rejected due to a lack of permissions

Parameters:response – The response from RT
Returns:True if the request was rejected
rt.api.search_tickets(query)[source]

Obtain a list of RT tickets matching the specified query (works with pagination)

Parameters:query – The TicketSQL query to use for the search
Returns:A list of ticket ids

Search for tickets in RT. You must provide a value for at least one of the following: requestor, owner, queue

Parameters:
  • requestor – Email address of the user that submitted the tickets
  • owner – Email address of the user the tickets have been assigned to
  • queue – Name of the RT queue (i.e. Database, Repairs, etc.)
  • status – Filter by ticket status (i.e. New, Open, __Active__, etc.) [Optional]
Returns:

A list of ticket ids

rt.api.ticket_comment(ticket_id, comments, notify=False, token=None)[source]

Comment on a ticket in RT

Parameters:
  • ticket_id – The ticket’s ID #
  • comments – Comments to add to the ticket
  • notify – If True, comments will also be sent to watchers via email
  • token – Provide token if available (Comment will be posted anonymously otherwise)
Returns:

API response

rt.api.ticket_history(ticket_id, simple=True, token=None)[source]

Retrieve ticket history information from RT

Parameters:
  • ticket_id – The ticket’s ID #
  • simple – If False, the response will contain more detailed information
  • token – RT Auth Token (uses the General account token if not provided)
Returns:

Dictionary - Contains a list of dictionaries with ticket history information

rt.api.update_ticket(ticket_id, token, status=None, owner=None)[source]

Update a ticket’s metadata in RT

Parameters:
  • ticket_id – The ticket’s ID #
  • token – Auth token to authenticate the request with
  • status – The new status to assign to the ticket (if applicable). Must match the available options in RT.
  • owner – The email address of the user to assign the ticket to (if applicable)
Returns:

API response


Views

Walks the user through connecting their RT account to their LNLDB account

rt.views.new_ticket(request)[source]

Form for submitting an RT ticket to the Database queue


Forms

class rt.forms.AuthTokenForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, field_order=None, use_required_attribute=None, renderer=None)[source]
class Meta[source]
layout = [('Text', "To continue, you'll need to create an Auth Token in RT. For instructions on how to do this, <a href='https://lnldb.readthedocs.io/en/latest/help/accounts/linking-rt.html'>click here</a>.<br><br>"), ('Field', 'token')]
base_fields = {'token': <django.forms.fields.CharField object>}
declared_fields = {'token': <django.forms.fields.CharField object>}
media
class rt.forms.TicketSubmissionForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, field_order=None, use_required_attribute=None, renderer=None)[source]
class Meta[source]
layout = [('Text', "<span style='color: grey'><em>Your name and contact information will automatically be shared with our support team when you submit this form.</em></span><br><br>"), ('Field', 'subject'), ('Field', 'description'), ('Field', 'attachments')]
base_fields = {'attachments': <multiupload.fields.MultiFileField object>, 'description': <django.forms.fields.CharField object>, 'subject': <django.forms.fields.CharField object>}
declared_fields = {'attachments': <multiupload.fields.MultiFileField object>, 'description': <django.forms.fields.CharField object>, 'subject': <django.forms.fields.CharField object>}
media

Slack

This module connects the LNLDB with our Slack workspace using the Slack API. This integration relies on our own custom app (a bot) which has already been installed into the workspace.

Models

class slack.models.ReportedMessage(*args, **kwargs)[source]

Used when users report problematic Slack messages

Parameters:
  • id (AutoField) – Id (required)
  • message (ForeignKey to SlackMessage) – Message (required)
  • comments (TextField) – Comments
  • reported_by (CharField) – Reported by (required)
  • reported_on (DateTimeField) – Reported on (required)
  • resolved (BooleanField) – Resolved (default=False)
exception DoesNotExist
exception MultipleObjectsReturned
comments

TextField(blank=True, null=True)

get_next_by_reported_on(*, field=<django.db.models.fields.DateTimeField: reported_on>, is_next=True, **kwargs)
get_previous_by_reported_on(*, field=<django.db.models.fields.DateTimeField: reported_on>, is_next=False, **kwargs)
id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

message

ForeignKey(related_name=”reports”, on_delete=CASCADE(), to= SlackMessage)

message_id

Raw (integer) FK for message

objects = <django.db.models.manager.Manager object>
reported_by

CharField(max_length=12)

reported_on

DateTimeField(auto_now_add=True)

resolved

BooleanField(default=False)

class slack.models.SlackMessage(*args, **kwargs)[source]

Used for archiving slack messages

Parameters:
  • id (AutoField) – Id (required)
  • posted_to (CharField) – Posted to (required)
  • posted_by (CharField) – Posted by (required)
  • content (TextField) – Content (required)
  • blocks (BooleanField) – Blocks (default=False)
  • ts (CharField) – Timestamp (required)
  • public (BooleanField) – Public (default=True)
  • parent (ForeignKey to SlackMessage) – Parent
  • deleted (BooleanField) – Remove from the Slack workspace? This action cannot be undone. (default=False)
exception DoesNotExist
exception MultipleObjectsReturned
blocks

BooleanField(default=False)

content

TextField()

deleted

BooleanField(verbose_name=”Remove from workspace”, default=False, help_text=”Remove from the Slack workspace? This action cannot be undone.”)

Remove from workspace: Remove from the Slack workspace? This action cannot be undone.

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
parent

ForeignKey(blank=True, null=True, on_delete=CASCADE(), to= SlackMessage)

parent_id

Raw (integer) FK for parent

posted_by

CharField(max_length=24)

posted_to

CharField(max_length=128)

public

BooleanField(default=True)

reports

Reverse Manager for slack.ReportedMessage’s message

slackmessage_set

Reverse Manager for slack.SlackMessage’s parent

ts

CharField(verbose_name=”Timestamp”, max_length=24)


API Methods

slack.api.channel_info(channel_id)[source]

Retrieves all the information about a channel

Parameters:channel_id – The ID of the channel
Returns:Channel details (Dictionary)
slack.api.check_presence(user)[source]

Gets user presence information from Slack (“active” or “away”)

Parameters:user – The identifier of the specified user
Returns:True if user is currently active, False if user is away
slack.api.delete_file(id)[source]
slack.api.handle_event(request)[source]

Event endpoint for the Slack API. Slack will send POST requests here whenever certain events have been triggered.

slack.api.handle_interaction(request)[source]

Interaction endpoint for the Slack API. Slack will send POST requests here when users interact with a shortcut or interactive component.

slack.api.join_channel(channel)[source]

If the app gets the ‘not_in_channel’ error when accessing a public channel, call this method

Parameters:channel – The channel to join
Returns:Response object (Dictionary)
slack.api.load_channels(archived=False)[source]

Get a list of all the public channels in Slack

Parameters:archived – Boolean - Include archived channels
Returns:Response object (Dictionary)
slack.api.lookup_user(email)[source]

Will search for a user in the Slack workspace using their email address

Parameters:email – The email address for the user
Returns:The identifier for the user in Slack (None if the search returns nothing)

Get a permalink for a specific message in Slack.

Parameters:
  • channel – The channel the message was posted in
  • message_id – The timestamp of the message
Returns:

Permalink URL

slack.api.message_react(channel, message, reaction)[source]

React to a Slack message

Parameters:
  • channel – The channel the message was posted to
  • message – The timestamp of the message
  • reaction – The name of the emoji to react to the message with
Returns:

Response object (Dictionary)

slack.api.message_unreact(channel, message, reaction)[source]

Remove a reaction from a Slack message

Parameters:
  • channel – The channel the message was posted to
  • message – The timestamp of the message
  • reaction – The name of the emoji to remove from the message
Returns:

Response object (Dictionary)

slack.api.open_modal(trigger_id, blocks)[source]

Opens a modal view (in Slack) in response to user action

Parameters:
Returns:

View ID if successful; None otherwise

slack.api.post_ephemeral(channel, text, user, username=None)[source]

Send an ephemeral message to a user in a channel. This message will only be visible to the target user.

Parameters:
Returns:

Response object (Dictionary)

slack.api.refresh_ticket_message(channel, message)[source]

Update a TFed ticket message with the latest information

Parameters:
  • channel – The channel the ticket was posted to
  • message – The original message object
Returns:

Response from Slack API after attempting to update the message

slack.api.replace_message(channel, message_id, text=None, content=None)[source]

Replace an existing message in Slack. The message will need to have been published by the bot.

The text parameter is not required when the content parameter is provided, however including it is still highly recommended.

Parameters:
Returns:

Response object (Dictionary)

slack.api.retrieve_message(channel, message_id)[source]

Retrieve a single message from Slack

Parameters:
  • channel – The channel the message was posted to
  • message_id – The timestamp of the message
Returns:

The message details

slack.api.slack_post(channel, thread=None, text=None, content=None, username=None, icon_url=None, attachment=None)[source]

Post a message on Slack

The text parameter is not required when the content parameter is provided, however including it is still highly recommended.

Parameters:
  • channel – The identifier of the Slack conversation to post to
  • thread – The timestamp of another message to post this message as a reply to
  • text – Message text (Formatting: https://api.slack.com/reference/surfaces/formatting)
  • content – List of valid blocks data (https://api.slack.com/block-kit)
  • username – Name displayed by the bot
  • icon_url – The URL to an image / icon to display next to the message (profile picture)
  • attachment – Dictionary with file details - {‘name’: ‘Example File’, ‘filepath’: ‘/media/slack/example.pdf’}
Returns:

Response object (Dictionary)

slack.api.upload(attachment, filename, title=None, message=None, channels=None)[source]

Upload a new file to Slack

Parameters:
  • attachment – File path to the file
  • filename – Filename with file extension (i.e. example.pdf)
  • title – Title of the file to display in Slack
  • message – The message text introducing the file in the specified channels
  • channels – Comma-separated list of channel names or ids where the file should be posted (i.e. C1234567890)
Returns:

Response object (Dictionary)

slack.api.user_add(channel, users)[source]

Invite users to join a slack channel. The bot must be a member of the channel.

Parameters:
  • channel – The identifier of the Slack channel to invite the users to
  • users – The identifiers of the specified users (List of up to 1000)
Returns:

Response object (Dictionary)

slack.api.user_kick(channel, user)[source]

Remove a user from a slack channel. The bot must be a member of the channel.

Parameters:
  • channel – The identifier of the Slack channel to remove users from
  • user – The identifier of the specified user
Returns:

Response object (Dictionary)

slack.api.user_profile(user_id)[source]

Get basic user profile information

Parameters:user_id – The identifier for the user in Slack (i.e. U123456789)
Returns:Slack user info (Dictionary)

Views

slack.views.app_home(tickets)[source]

Blocks for the App’s Home tab. Generated using the Block Kit Builder (https://app.slack.com/block-kit-builder)

Parameters:tickets – A list of ticket ids
slack.views.cc_add_notification(cci)[source]

Blocks for a Crew Chief add notification. Generated using the Block Kit Builder (https://app.slack.com/block-kit-builder)

Parameters:cci – EventCCInstance object
slack.views.cc_report_reminder(cci)[source]

Blocks for a missing crew chief report reminder Generated using the Block Kit Builder (https://app.slack.com/block-kit-builder)

Parameters:cci – EventCCInstance object
slack.views.event_edited_notification(event, triggered_by, fields_changed)[source]

Blocks for an event edited Slack notification. Generated using the Block Kit Builder (https://app.slack.com/block-kit-builder)

Parameters:
  • event – The event object
  • triggered_by – The user that edited the event
  • fields_changed – A list of fields that have changed
slack.views.generate_button(text, value, style='default', emoji=False, action_suffix='action')[source]

Generate a Block Kit button

Parameters:
  • text – The button text
  • style – Style of button (Must be “default”, “primary”, or “danger”)
  • value – Button value
  • emoji – Boolean indicating whether or not to permit emoji in the button text
  • action_suffix – Defaults to “action”. Will be appended to value to create action_id
Returns:

Button block dictionary

slack.views.generate_modal(title, callback_id, blocks)[source]

Generate a modal view object using Slack’s BlockKit

Parameters:
  • title – Title to display at the top of the modal view
  • callback_id – Identifier used to help determine the type of modal view in future responses
  • blocks – Blocks to add to the modal view
Returns:

View object (Dictionary)

slack.views.report_list(request)[source]

View Slack messages reported for moderation

slack.views.report_message_modal(message)[source]

Blocks for the modal view that is displayed when a user reports a problematic Slack message. Generated using the Block Kit Builder (https://app.slack.com/block-kit-builder)

Parameters:message – A SlackMessage object representing the message
slack.views.reported_message_notification(sender, report)[source]

Blocks for the notification sent to the Webmaster whenever a new report is submitted. Generated using the Block Kit Builder (https://app.slack.com/block-kit-builder)

Parameters:
  • sender – The Slack ID for the user that sent the report
  • report – The corresponding ReportedMessage object
slack.views.tfed_modal()[source]

Blocks for the TFed ticket submission form. Generated using the Block Kit Builder (https://app.slack.com/block-kit-builder)

slack.views.tfed_ticket(ticket)[source]

Generate blocks for TFed ticket response message. Generated using the Block Kit Builder (https://app.slack.com/block-kit-builder)

slack.views.ticket_comment_modal(ticket_id)[source]

Blocks for the TFed ticket comment modal. Can be launched in the App Home tab. Generated using the Block Kit Builder (https://app.slack.com/block-kit-builder)

slack.views.ticket_update_modal(ticket_id, channel, timestamp, action)[source]

Blocks for the TFed ticket update form. Generated using the Block Kit Builder (https://app.slack.com/block-kit-builder)

Parameters:
  • ticket_id – The ticket # for the ticket being updated
  • channel – The channel the ticket is being updated from
  • timestamp – The timestamp of the message that triggered this action
  • action – The type of update operation (Options: ‘open’, ‘update’, ‘close’)
slack.views.view_report(request, pk)[source]

View full report for a Slack message that has been flagged for moderation

slack.views.welcome_message()[source]

Blocks for the Welcome Message. This message will be displayed to new users joining the Slack workspace. Generated using the Block Kit Builder (https://app.slack.com/block-kit-builder)

Spotify

This module connects the LNLDB with LNL’s Spotify accounts via the Spotify Web API. Note that this integration is not currently available for use with personal Spotify accounts.

Models

class spotify.models.Session(*args, **kwargs)[source]

Spotify song request session for a specific event

Parameters:
  • id (AutoField) – Id (required)
  • event (ForeignKey to Event2019) – Event (required)
  • accepting_requests (BooleanField) – Accepting requests (default=True)
  • allow_explicit (BooleanField) – Allow explicit (default=True)
  • auto_approve (BooleanField) – Auto approve (default=False)
  • require_payment (BooleanField) – Require payment (default=False)
  • allow_silence (BooleanField) – Allow silence (default=False)
  • private (BooleanField) – Private (default=False)
  • user (ForeignKey to SpotifyUser) – User (required)
  • slug (SlugField) – Slug (required)
  • paypal (URLField) – PayPal.Me Link
  • venmo (CharField) – Venmo username
  • venmo_verification (CharField) – Venmo verification
exception DoesNotExist
exception MultipleObjectsReturned
accepting_requests

BooleanField(default=True)

allow_explicit

BooleanField(default=True)

allow_silence

BooleanField(default=False)

auto_approve

BooleanField(default=False)

event

ForeignKey(on_delete=CASCADE(), to= Event2019)

event_id

Raw (integer) FK for event

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
paypal

CharField(blank=True, null=True, help_text=”PayPal.Me Link”)

Paypal: PayPal.Me Link

private

BooleanField(default=False)

requests

Reverse Manager for spotify.SongRequest’s session

require_payment

BooleanField(default=False)

save(*args, **kwargs)[source]

Save the current instance. Override this in a subclass if you want to control the saving process.

The ‘force_insert’ and ‘force_update’ parameters can be used to insist that the “save” must be an SQL insert or update (or equivalent for non-SQL backends), respectively. Normally, they should not be set.

slug

SlugField(max_length=128, unique=True)

user

ForeignKey(on_delete=CASCADE(), to= SpotifyUser)

user_id

Raw (integer) FK for user

venmo

CharField(max_length=16, blank=True, null=True, help_text=”Venmo username”)

Venmo: Venmo username

venmo_verification

CharField(max_length=4, blank=True, null=True)

class spotify.models.SongRequest(*args, **kwargs)[source]

Used in keeping track of a song request

Parameters:
  • id (AutoField) – Id (required)
  • session (ForeignKey to Session) – Session (required)
  • name (CharField) – Name (required)
  • identifier (CharField) – Identifier (required)
  • duration (IntegerField) – Duration in ms (required)
  • approved (BooleanField) – Approved (default=False)
  • queued (DateTimeField) – Queued
  • paid (BooleanField) – Paid (default=False)
  • submitted_by (CharField) – Submitted by (required)
  • email (EmailField) – Email
  • phone (CharField) – Phone
exception DoesNotExist
exception MultipleObjectsReturned
approved

BooleanField(default=False)

duration

IntegerField(help_text=”Duration in ms”)

Duration: Duration in ms

email

CharField(max_length=254, blank=True, null=True)

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

identifier

CharField(max_length=32)

name

CharField(max_length=150)

objects = <django.db.models.manager.Manager object>
paid

BooleanField(default=False)

phone

CharField(max_length=24, blank=True, null=True)

queued

DateTimeField(blank=True, null=True)

session

ForeignKey(related_name=”requests”, on_delete=CASCADE(), to= Session)

session_id

Raw (integer) FK for session

submitted_by

CharField(max_length=150)

class spotify.models.SpotifyUser(*args, **kwargs)[source]

Represents a user’s Spotify Account. Authentication tokens will be saved here.

Parameters:
  • id (AutoField) – Id (required)
  • user (ForeignKey to User) – User (required)
  • display_name (CharField) – Display name
  • spotify_id (CharField) – Spotify id
  • token_info (TextField) – Token info
  • personal (BooleanField) – Uncheck this for shared club accounts (default=True)
exception DoesNotExist
exception MultipleObjectsReturned
display_name

CharField(max_length=150, blank=True, null=True)

id

AutoField(verbose_name=”ID”, primary_key=True, serialize=False, auto_created=True)

objects = <django.db.models.manager.Manager object>
personal

BooleanField(default=True, help_text=”Uncheck this for shared club accounts”)

Personal: Uncheck this for shared club accounts

session_set

Reverse Manager for spotify.Session’s user

spotify_id

CharField(max_length=150, blank=True, null=True)

token_info

TextField(blank=True, null=True)

user

ForeignKey(related_name=”spotify_accounts”, on_delete=CASCADE(), to= User)

user_id

Raw (integer) FK for user


API Methods

class spotify.api.DjangoCacheHandler(user, account_id=None)[source]

Custom Spotipy cache handler. Saves authentication information to the database.

get_cached_token()[source]

Get and return a token_info dictionary object.

save_token_to_cache(token_info)[source]

Save a token_info dictionary object to the cache and return None.

exception spotify.api.SpotifySessionError(message, error=None, error_description=None, *args, **kwargs)[source]
spotify.api.add_to_queue(song_request, request_user)[source]

Attempt to add a track to the Spotify queue

Parameters:
  • song_request – Song request object
  • request_user – The user currently logged in (User object)
Returns:

None on success; SpotifyException otherwise

spotify.api.get_available_devices(account)[source]

Retrieves information about a Spotify user’s available devices

Parameters:account – The corresponding SpotifyUser object
Returns:Device info (List of Dictionaries)
spotify.api.get_currently_playing(session)[source]

Attempts to get details about what is currently playing in Spotify

Parameters:session – The corresponding Session object
Returns:Item metadata, if available (Dictionary)
spotify.api.get_playback_state(session)[source]

Retrieves information about the session’s current playback state

Parameters:session – The corresponding Session object
Returns:Playback state information (Dictionary)
spotify.api.get_spotify_session(account, request_user)[source]

Call this method to get a Spotify session for a specific Spotify account.

Parameters:
  • account – SpotifyUser object
  • request_user – The user currently logged in (User object)
Returns:

A Spotify object (manages the session and API calls)

spotify.api.get_track(session, identifier)[source]

Retrieves the metadata for a given item in Spotify

Parameters:
  • session – A Session object (used for authenticating the request)
  • identifier – The unique Spotify ID for the item
Returns:

Item metadata, if available (Dictionary)

spotify.api.pause(session)[source]

Pause playback for a given session.

Parameters:session – The corresponding Session object
Returns:None (if successful); Error message otherwise (string)
spotify.api.play(session, device=None)[source]

Starts or resumes playback for a given session.

Parameters:
  • session – The corresponding Session object
  • device – The unique id of the device to start playback on
Returns:

None (if successful); Error message otherwise (string)

spotify.api.previous(session)[source]

Skip to the previous track.

Parameters:session – The corresponding Session object
Returns:None (if successful); Error message otherwise (string)
spotify.api.queue_estimate(session, ms=False)[source]

Attempt to determine wait time for new song requests

Parameters:
  • session – The corresponding Session object
  • ms – If True, return the estimate in milliseconds
Returns:

Time remaining, if available (Int)

spotify.api.skip(session)[source]

Skip to the next track.

Parameters:session – The corresponding Session object
Returns:None (if successful); Error message otherwise (string)

Views

spotify.views.approve_request(request, pk)[source]

Approve a song request (POST only)

spotify.views.auth_callback(request)[source]

Handle Spotify authentication callback

spotify.views.cancel_request(request, pk)[source]

Deny a song request (POST only)

spotify.views.configure_session(request, event_id)[source]

Set up a Spotify shared listening session and begin accepting song requests for an event

Parameters:event_id – The primary key value of the event the session is attached to
spotify.views.generate_qr_code(request, session_id)[source]

Generate a QR Code

Parameters:session_id – The primary key value of the shared listening session
spotify.views.login(request)[source]

Authenticate a user against the Spotify API

spotify.views.paid(request, pk)[source]

Mark a song request as paid (if applicable). POST only.

spotify.views.pay_fee(request, session_id)[source]

If payment is required when making a song request, this page should be displayed.

Parameters:session_id – The primary key value of the session object
spotify.views.queue_manager(request, session)[source]

Manage or view song requests

Parameters:session – The primary key value of the session object
spotify.views.queue_song(request, pk)[source]

Add a song to the Spotify session queue (POST only)

Parameters:pk – The primary key value of the corresponding song request
spotify.views.song_request(request, session_id)[source]

Page for accepting song requests

Parameters:session_id – The unique slug for the corresponding session

Forms

class spotify.forms.SongRequestForm(session, *args, **kwargs)[source]
class Meta[source]
fields = ('email', 'phone')
model

alias of spotify.models.SongRequest

base_fields = {'email': <django.forms.fields.EmailField object>, 'first_name': <django.forms.fields.CharField object>, 'last_name': <django.forms.fields.CharField object>, 'phone': <django.forms.fields.CharField object>, 'request_type': <django.forms.fields.ChoiceField object>}
clean()[source]

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

declared_fields = {'first_name': <django.forms.fields.CharField object>, 'last_name': <django.forms.fields.CharField object>, 'request_type': <django.forms.fields.ChoiceField object>}
media
class spotify.forms.SpotifySessionForm(request_user, *args, **kwargs)[source]
class Meta[source]
fields = ('user', 'accepting_requests', 'allow_explicit', 'require_payment', 'auto_approve', 'private', 'allow_silence', 'paypal', 'venmo', 'venmo_verification')
model

alias of spotify.models.Session

base_fields = {'accepting_requests': <django.forms.fields.BooleanField object>, 'allow_explicit': <django.forms.fields.BooleanField object>, 'allow_silence': <django.forms.fields.BooleanField object>, 'auto_approve': <django.forms.fields.BooleanField object>, 'paypal': <django.forms.fields.URLField object>, 'private': <django.forms.fields.BooleanField object>, 'require_payment': <django.forms.fields.BooleanField object>, 'user': <django.forms.models.ModelChoiceField object>, 'venmo': <django.forms.fields.CharField object>, 'venmo_verification': <django.forms.fields.CharField object>}
clean_paypal()[source]
declared_fields = {'auto_approve': <django.forms.fields.BooleanField object>, 'paypal': <django.forms.fields.URLField object>, 'private': <django.forms.fields.BooleanField object>, 'user': <django.forms.models.ModelChoiceField object>, 'venmo_verification': <django.forms.fields.CharField object>}
media

Release Notes

Updates 2022

September

This month brought a roll-up of updates from over the summer.

  • @02543fd Spotify integration
  • @2549976 Fix autocomplete for “Add new row”
  • @0681c6a Place sensible bounds on class year (no less than 1962, no more than $CURRENT_YEAR + 6)
February

This month brought in more bug fixes and minor improvements. We also started taking some initial steps toward a more modern UI for the LNLDB with a new login page.

January

We kicked off the new year in a big way! Several long-awaited bug fixes and UI improvements were finally introduced this month, including a redesigned bulk checkin and checkout feature for rentals. We also introduced the ability to automatically send calendar invites for meetings (if users choose to opt in).

  • @9b656ed File added notifications now work with the Ignore my actions setting
  • @8c7fdd6 Poke for CC messages now include the officer’s title rather than defaulting to VP
  • @77d4600 Fixes an issue where bcc on calendar invite emails was working incorrectly (#598)
  • @a656a6f RT tickets submitted through the LNLDB now include a user’s full name
  • @89f3d31 Fixed a timezone bug found in calendar invites
  • @2a0ac4b Corrected the sort order of several event listings
  • @2670226 Redesigned Snipe checkin and checkout for better error handling
  • @b2888c5 Added automated calendar invites for meetings (opt-in required)
  • @2d4754a New permission denied page with the option to submit a ticket
  • @25266a2 Completed the API token request endpoint
  • @49121da Send Slack notification when submitting RT tickets through the LNLDB
  • @9c19517 Added the ability for the Slack app to automatically join new public channels

Updates 2021

December

To end the year, we tested out some new moderation tools for Slack and upgraded the API documentation to support the OpenAPI specification. As always there were also a few bug fixes and UI improvements.

  • @7d655fe Added new API documentation that supports the OpenAPI specification
  • @795c810 Updated the survey dashboard graphs to exclude scores of -1 (#545)
November

In November we switched from Travis CI to GitHub Actions and deployed several bug fixes, UI improvements, and new features. Among these new features was a user preferences page for LNL members. This gives our members more control over what types of communications they receive from us.

  • @ccbeab8 Added a Slack DM link to user profiles
  • @7d89902 Improved MDM software management features
  • @d999568 Added automatic Slack channel linking
  • @9ac61ac Added new crew chief resources to ‘CC Add’ email (#544)
  • @d3d8e89 Added the ability to archive old meeting types
  • @416c286 Added category labels to hour listings on member profiles (#563)
  • @c3da368 Fixes a bug where event classification icons were not supported for 2019 Events (#509)
  • @940f7f9 Switch from Travis CI to GitHub Actions
October

This month was spent working on several small bug fixes and UI improvements. We also added the ability for users to add their pronouns to their profiles.

  • @687e2d8 Resolves an issue where Committee Leaders could access closed meeting minutes
  • @136ed7f Updated markdown format settings (#547, #551)
  • @6bd78e5 Fixed the events list on the meeting details page to work with 2019 Events
September

We took care of several minor dependency updates and bug fixes. A few languishing feature requests were also completed.

  • @812ed05 Added a badge to event lists to indicate test events (#432)
  • @b084af2 Corrects the issue that prevented upcoming events from appearing in the form for meeting notices (#479)
  • @09841da Adds a delete button to the meeting edit form (#434)
August

In August we released the beta of our new Slack integration. Users can now view and submit TFed tickets through Slack. Privileged RT users can also link their accounts to manage those tickets.

  • @b5e10da Added support for the integration’s Home tab in Slack
  • @c4a682a Fixed a bug where post-event surveys could be sent for cancelled events
  • @dca9d11 Post-Event surveys are now sent by default
  • @b1f6900 Added a welcome message for new Slack users
July

This month we introduced the initial version of the RT integration for the LNLDB. Users can now submit TFed tickets from our error page.

  • @7eaab31 Fixed a bug where meeting titles occasionally displayed the wrong date
  • @fdb146f Add form for submitting tfed tickets (#525)
June

This month our main focus was on smaller features, UI improvements, and bug fixes. We also finally completed the transition to Workday for billing. The old Banner funds are now no longer supported.

  • @dba1d50 Fixed a bug where event attachments were not being linked to the selected services
  • @1441bb7 Deprecated Banner funds (completes the transition to Workday for billing)
  • @aa22a4b Officers can now specify a location for their office hours
  • @9dccb7c Updated our email template to include links to our Instagram and YouTube accounts
  • @efab3e9 Added calendar invites to meeting notice emails
  • @cf5843d Fixed a bug where the date was sometimes incorrect in the heading of meeting notice emails
  • @7d8c20c Updated welcome email (Upper Perreault Hall is now spelled correctly)
May

We finally launched our User Guides! They are now available here. Other than that, our focus this month was on bug fixes and other long-awaited improvements.

  • @b1e84e8 Obtain member Student IDs automatically
  • @816a5bd Made Snipe accessible to active members
April

In April we began chipping away at a long list of small bug fixes and UI improvements requested by our users. We also began laying the groundwork for our new Slack integration (coming soon)!

  • @89fea1a Allow crew chiefs to view post-event survey results
  • @072ce30 Fixed a bug in the formatting of PDF invoices and quotes
  • @ab29ef5 Removed the old fund field from the client request form
  • @846ba14 Corrected a few errors that prevented the Snipe Checkin/Checkout tools from accessing the API
March

This month we launched our new onboarding system. Aside from that we fixed a few bugs and carried out some small improvements to the UI.

  • @24a0646 Added an unsubscribe link to some of our automated emails
  • @a31275a Fixed a bug where HTML tags were visible in PIT request emails
  • @88b1e75 Fixed a bug that occurred on the lnl.wpi.edu/me page when a user was not logged in
  • @a51d990 Fixed a bug affecting the layout of the meeting email form
  • @44ab3c3 Added a more user friendly login failed page for Microsoft SSO
February

In February we dropped support for python 2 and began updating these docs. Our docs now have a new theme and include significantly more helpful information!

  • @79e40f1 Dropped support for python 2 and added support for Django 2.2 or later
  • @5d0e106 Added a complete button for PIT requests
  • @4f983c4 Added outlook invites to crew chief add notifications
  • @74056d7 Fixed a timezone bug in the new poke for crew chief feature
  • @c0786f6 Added a button in the laptops list for requesting managed software

Updates 2020

November

This month we removed support for WPI’s Central Authentication Service (CAS). Users no longer have the ability to sign in using CAS.

October

For the first time in a long time (possibly ever), we were able to get our test coverage above 90%! We also deprecated the old workorder wizard.

August

We deployed a lot of new code in August! Here’s an overview of what changed:

  • @d3e6d90 Improved support for python 3 throughout
  • @dfb6d82 The Vice President now has the ability to send an email to the club poking for crew chiefs
  • @ab73196 Started building support for third-party extensions and 2FA
  • @d52535f Updated the API to support token-based authentication
  • @0ef4164 Launched the Event and Crew Member API endpoints
  • @e1574ea Made the old inventory system read-only; we now use Snipe for inventory tracking and management
  • Implemented new contact tracing features to support safe operations during the Coronavirus pandemic
  • Deployed the initial version (1.0.2) of the MDM
  • Various other bug fixes and minor UI improvements
June

In June we kicked off a couple major projects. The first was the start of preparations towards dropping support for python 2 as it had reached End of Life in January. We also began working on a new Mobile Device Management (MDM) platform for the LNL MacBooks, which will save the Webmaster countless hours managing them.

  • Started writing unit tests for the vast amounts of untested code
  • @13f91d9 Launched a new system for creating static pages quickly and conveniently using styles consistent with the new design for the static site
  • @b0b035f Officers can now upload headshots to their profiles for display on our about page
  • Began working on the new MDM platform
May

In May we switched over to HTTPS and added Microsoft SSO as a login option. WPI community members can now log into the LNL Database using their WPI Microsoft accounts with no further action required.

April

In April, we added the ability to manage listings for workshops. This replaced the previous version of the workshops page which was just a static webpage.

March

Here’s a general overview of some of the changes we made back in March.

  • @242117e Added the ability to send SMS text messages to LNL members (requires opt-in)
  • @d0e548b Include the cost of extras when calculating discounts
  • @979ce25 Launched a new REST API
  • @a07bbf6 Officers can now list their office hours on their profiles
  • Various other bug fixes and UI improvements

The new REST API provides access to some of the more popular portions of our database. You can find the API documentation here (login required).

February

Here’s a highlight of some of the new features we deployed back in February.

  • @77fe096 Update Admin Site UI with LNL branding
  • @7db6ce9 Add away status expiration dates
  • @b7feba3 Projectionists can now request PITs through the LNL database

Note

For updates prior to February 2020, we recommend taking a look at the project on Github.

License

MIT License

Copyright (c) 2022 WPI Lens and Lights

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Indices and tables