Skip to content

LCS API Endpoints

Lucent Fong edited this page Aug 22, 2021 · 14 revisions

The LCS API

This is an endpoint-by-endpoint listing of the LCS API with the parameters, details, and kinks written out.

Don't read this unless you have a specific question. Read the more general docs for a higher-level overview. The general ideas include something like a table of contents.

The error messages below are imprecise on dev (the dev and prod are slightly mismatched). The status codes are accurate and should be the only thing you use to check for an error condition - messages are intended for programmers, not the code.

/attend-event

Method: POST

Data: JSON

Example JSON:

{
    "auth_email": "email of the person checking people in",
    "token": "token belonging to auth_email",
    "qr": "qr of the person attending the event. (email or id)",
    "event": "name of the event being attended",
    "again": "optional. whether or not to allow attending an event twice"
}

Returns:

Situation Value HTTP Code Type
success {"email": "email matched", "new_count": 0 /*amount of times the event was attended*/} 200 application/json
user already attended. use "again": true to ignore user already checked into event 402 text/plain
user or qr not found user not found 404 text/plain

/authorize

Method: POST.

Data: JSON.

Example JSON:

{
    "email": "somebody@somewhere.com",
    "password": "the plain text password"
}

Returns:

Situation Value HTTP Code Type
Email or password not present in JSON. Invalid Request 400 Text/plain
No user with that email and password. invalid email,hash combo 403 Text/plain
The user is present, but used MLH. Please use MLH to log in. 403 Text/plain
The user is present, but the password does not match. invalid email,hash combo 403 Text/plain
Successful login {"auth": { "token": "some token", "valid_until": "ISO date for 3 days from now", "email": "the email passed in"}} 200 Application/JSON

Notes: The password is hashed in the processing - plain text is not in the DB. For security, however, you must use HTTPS so that user passwords cannot be intercepted.

/create

Method: POST.

Data: JSON.

Example JSON:

Minimal:


{
    "email": "some_email@some_site.com",
    "password": "the plain text password"
}

With a magic link:

{
    "email": "some_email@some_site.com",
    "link": "bibaty bobity boo",
    "password": "the plain text password"
}

Maximal:

{
    "email": "some_email@some_site.com",
    "password": "the plain text password"
    "github": "Their github",
    "major": "Their major",
    "short_answer": "Their short answer",
    "shirt_size": "Their shirt size",
    "first_name": "Their first name",
    "last_name": "Their last name",
    "dietary_restrictions": "Their dietary restrictions",
    "special_needs": "Their special needs",
    "date_of_birth": "Their date of birth",
    "school": "Their school",
    "grad_year": "Their grad year",
    "gender": "Their gender",
    "registration_status": "Their registration status",
    "level_of_study": "Their level of study",
    "slack_id": "Their unique slack id"
}

Returns:

Situation Value HTTP Code Type
Registration is closed Registration is closed 400 Text/plain
The email is invalid An error message explaining the email troubles. 400 Text/plain
No email No email provided! 400 Text/plain
No password provided. No password provided 400 Text/plain
The email is already in the DB Duplicate user! 400 Text/plain
Successful login {"auth": { "token": "some token", "valid_until": "ISO date for 3 days from now", "email": "the email passed in"}} 200 Application/JSON

The magic link can be optimally provided to consume a link on creation. This is convenient for some magiclinks. See the consume endpoint which is wholly subsumed by this.

/validate

Method: POST

Data: JSON

Example JSON:

{
    "email": "somebody@somewhere.com",
    "token": "the authentication token string"
}

Returns:

Situation Value HTTP Code Type
Invalid data submission Data not submitted 400 Text/plain
User email not found Email not found 403 Text/plain
User token expired Invalid token 403 Text/plain
Success The data submitted 200 Application/JSON

/update

Method: POST

Data: JSON

Example JSON:

{
  updates : {'$set': {'grad_year': 2020}},
  user_email: "somehacker@email_server.thing",
  auth_email: "somehacker@email_server.thing",
  auth: "the auth token"
}

This changes the Graduation year of the hacker (with email somehacker@your_hackathon.org) to 2020 (assuming the auth token is valid).

{
  updates : {'$set': {'registration_status': 'checked-in'}},
  user_email: "somehacker@email_server.thing",
  auth_email: "some_admin_email@your_hackathon.org",
  auth: "the auth token"
}

This changes the registration status of the user somehacker@your_hackathon.org if the user (admin - that is director or organizer) is some_admin_email@your_hackathon.org and the token is valid for the admin. We discuss the details of the permissions where we discuss the user object.

{
  updates : {'$set': {'day_of.checkIn': True, 'registration_status': 'checked-in'}},
  user_email: "somehacker@email_server.thing",
  auth_email: "some_admin_email@your_hackathon.org",
  auth: "the auth token"
}

Assuming the validity of the auth token and that auth_email is an organizer, this is the update an app should use when scanning a QR code to admit a hacker into the hackathon. $set against the day_of with fields that do not yet exist are simply added in. This is a convenience so that LCS does not need to be updated every time there is a new event that needs to be tracked.

{
  updates : {'$inc': {'day_of.lunch1': 1}},
  user_email: "somehacker@email_server.thing",
  auth_email: "some_admin_email@your_hackathon.org",
  auth: "the auth token"
}

This update would be performed when a user is scanned for lunch on Saturday. Lunch is the only meal that occurs twice and tends to be numbered, 1 being the Saturday one and 2 the one on Sunday. $inc increments since the food team may allow hackers to receive multiple servings. If the field is not there, MongoDB will set it to the value given (so, in this case 1, if it's the hacker's first time having lunch on Saturday).

Auth email vs. user email: In order to prevent users from updating their own status or letting any sort of malicious changes to a hacker's data, we distinguish updates between those allowed for admins and those allowed for hackers. The "auth email" is the email of the person performing the updates and the "user email" is the email of the user being updated.

Mongo docs (what $set is about): So this endpoint actually allows for any individual update (uniquely determining who to update by email). So we differ to Mongo to explain the operations you can put.. Most fields are all or nothing: if you can update the field, you can do anything to it. The only exception is the registration status which has its own FSM that determines update permissions.

Silent failures: If the change is not permitted by a validation issue, the endpoint silently does not change the field in question. Every field is considered separately - so if an update is more advanced, it may only partially go through. Check the user object for details on whether the hacker can update the status or if an admin is needed.

Returns:

Situation Value HTTP Code Type
Email, auth email or token (auth) not given Data not submitted. 400 Text/plain
Auth email is not found Auth email not found. 400 Text/plain
Auth token is not found Authentication token not found. 400 Text/plain
Auth email is not the hacker email and is not that of an admin Permission Denied 403 Text/plain
Hacker email not found User email not found 400 Text/plain
Success Successful Request 200 Text/plain

/consume

Method: POST

Data: JSON

Example JSON:

{
  link: 'the randomly generated magic link',
  email: 'hacker@email.thing',
  token: 'the auth token'
}

More on the use: Remember to see the general docs for how this interacts with the other endpoints to create its own updating system.

Returns:

Situation Value HTTP Code Type
link not given No magic link provided 400 Text/plain
link not found Invalid magiclink 400 Text/plain
The user is an MLH user (so we do not have control over their password) Please change your password through MLH 400 Text/plain
The user email is not found We could not find that email 400 Text/plain
A login issue occurred in handling the link (for a role update) Failed to update: please login again. 400 Text/plain
Password has been updated Successfully updated your password 200 Text/plain
Role has been updated Successfully updated your role 200 Text/plain

/createmagiclink

Method: POST

Data: JSON

Example JSON:

For a forgotten password:

{
  email: "some@email.thing,
  forgot: true
}

and to promote users:

{
  email: "some_director@your.hackathon",
  "token": "the user's token",
  "numLinks": 3,
  "permissions": ["director", "judge", "organizer", "volunteer", "mentor"],
  "emailsTo": ["first_to_promote@their_email.com", "second_to_promote@their_email.com", "third_to_promote@their_email.com"]
}

The numLinks parameter is optional - 1 by default. The emailsTo is necessary to email the promoted users so that they may be promoted.

More on the use: Remember to see the general docs for how this interacts with the other endpoints to create its own updating system. Also note that admins and hackers have very different uses: hackers may only request a password reset while admins may promote anybody. Additionally, there is no verification of the email being promoted and if that email is already that of a hacker.

Returns:

Situation Value HTTP Code Type
Valid forgotten password case Forgot password link has been emailed to you 200 Text/plain
The user is an MLH user - we don't have their password Please use MLH to login. 400 Text/plain
The user is not a user - they must create an account Invalid email: please create an account. 400 Text/plain
The admin user did not provide enough information for the link You forgot some params try a again 400 Text/plain
The admin user was not enough of an admin Invalid permissions 400 Text/plain
The admin user could not be logged in Please input a proper auth token 400 Text/plain
Valid director link case List of magic link objects - see below. 200 Application/JSON

The magic link object:

{
  "permissions": ["director", "judge", "organizer", "volunteer", "mentor"]
  "email": "someuser@your_hackathon.org"
  "forgot": false,
  "link": "a hashy boi",
  "valid_until": "UTC time now + 3 hours"
}

/dayof-events

Method: GET

Data: JSON

Example Uses: Just a plain ol' GET:

    GET http://your-deploy.execute.amazonaws.com/dayof-events

You can pass a num_events to influence the number of events shown (defaults to 10).

Returns:

Situation Value HTTP Code Type
The calendar API is misconfigured Please interactively generate client secret file. 400 Text/plain
The calendar API returned an error Unable to get events. 400 Text/plain
Success Google API events. The events are returned as specified by google. 200 Application/JSON

/dayof-slack

Method: GET

Data: JSON

Example Uses: Just a plain ol' GET:

    GET http://your-deploy.execute.amazonaws.com/dayof-slack

You can pass a num_events to influence the number of events shown (defaults to 10).

Returns:

Situation Value HTTP Code Type
The slack API returned an error Unable to retrieve messages 400 Text/plain
The slack API returned no messages No messages found. 400 Text/plain
Success Slack messages that are not "join" messages. The messages are returned as specified by slack. 200 Application/JSON

/send-emails

Method: POST

Data: JSON

Example JSON:

A user emailing themselves:

{
  "template": "some sparkpost template",
  "recipients": ["some_email@your.hackathon"],
  "email": "some_email@your.hackathon",
  "token": "some hashy boi"
}

A user (director) emailing two people:

{
  "template": "some sparkpost template",
  "recipients": ["some_email@your.hackathon", "some_other_email@your.hackathon"],
  "email": "some_director@your.hackathon",
  "token": "some hashy boi"
}

A user (director) emailing by a query (are they a judge):

{
  "template": "some sparkpost template",
  "query": {'role.judge': true}
  "email": "some_director@your.hackathon",
  "token": "some hashy boi"
}

A user (director) emailing people with personalised links:

{
  "template": "some sparkpost template",
  "recipients": ["some_email@your.hackathon", "some_other_email@your.hackathon"],
  "links": ["https://your-hackathon.org/link-1", "https://your-hackathon.org/link-2"],
  "email": "some_director@your.hackathon",
  "token": "some hashy boi"
}

Constraints: The query or a list of recipients that is not just the user's email itself can be submitted by directors only. Additionally, links can only be provided with recipients. This is since the number of results in a query cannot be known, so the correct number of links would likely not be provided.

Returns: There are 4 classes of errors and the messages are rather self-explanatory:

  • An issue with the invocation: either missing data or lacking permission. Note that users may only email themselves, directors can email anybody. An empty list of recipients is caught here too.
  • An issue with sparkpost: invalid templates, or any sort of malarchy. The error string will be from sparkpost except in deeply pathological cases.
  • An issue with the query: if the user passes in a query, it might have an issue which will be reported.
  • An issue with personalised links.

/link-qr

Method: POST

Data: JSON

Example JSON:

{
    "auth_email": "email of the user doing the link",
    "token": "one hashy boi",
    "email": "the hacker being linked",
    "qr_code": "value of a qr. an email or id string"
}

Returns:

Situation Value HTTP Code Type
success success 200 text/plain
not authorized. or bad role permission denied 403 text/plain
user not found user not found 404 text/plain

/read

Method: POST

Data: JSON

Example JSON:

There could be a user:

{
  "email": "users_email@your_hackathon",
  "token": "some hashy boi",
  "query": {"email": "their email"}
}

and then they can aggregate (counting the shirt sizes and genders):

{
  "email": "users_email@your_hackathon",
  "token": "some hashy boi",
  "query": ["shirt-size", "gender"],
  "aggregate": true
}

and there may not even be a user:

{
  "query": ["shirt-size", "gender"],
  "aggregate": true,
  "just_here": true
}

Returns

The old validation rules were clumsy at best. There are three types of queries, explained in decreasing power:

  1. A director query: directors are allowed to run any query. We only ensure that non-serializable Mongo stuff is not included.
  2. A user query: users can get themselves (only). (So the validate endpoint is good enough.) Redacts reimbursement information on hackers who aren't confirmed.
  3. A non-director aggregation: anybody (regardless of relation to LCS) can aggregate by the powerset of these fields: major, shirt_size, dietary_restrictions, school, grad_year, gender, level_of_study, ethnicity. This will create counts of every combination of the field values found in the database. The just_here field is a flag on whether to exclude non-checked in users.

/resume

Method: POST

Data: JSON

Example JSON:

{
  "email": "users_email@your_hackathon",
  "token": "some hashy boi",
}

Returns

  1. send resume to s3 by doing a PUT request to the upload url Content-Type header must be set to application/pdf.
  2. get resume from s3 by doing a GET request to the upload url.
  3. if we have the resume exists will be true.
{
  "upload": "url",
  "download": "url",
  "exists": true|false,
}

/reimburse

Method: POST

Data: JSON

Example JSON:

{
  "email": "director@place.com",
  "token": "hashy boi"
}

Returns

Mostly changes the DB to include reimbursement estimates to travelling users. Uses the google distance matrix API and configurable cost-per-mile constants.

The error messages are generated by the various libraries and APIs: there can be google maps API errors, Mongo query errors, and errors in the JSON sent in. Only directors can call the API. On success, the write operation result and the amount spent are returned in JSON. For example:

{"statusCode": 200, "mongo_result": 60, "total": 3000}

/slack-dm

Method: POST

Data: JSON

Example JSON:

{
  "email": "director@place.com",
  "token": "hashy boi",
  "other_email": "hacker@hackathon.com"
}

Returns

Situation Value HTTP Code Type
Email not found in LCS User Not Found 403 Text/plain
Auth token is invalid Token invalid 403 Text/plain
Other email not found in LCS Other user not found within LCS 403 Text/plain
Slack API token missing Slack API token not configured 503 Text/plain
Slack id of one or both users not in LCS Slack ID not present within LCS for the given user(s) 403 Text/plain
Slack API request error Encountered a Slack API error 503 Text/plain
Slack API error (related to users) There was an error with the user id's provided: {error_str}
The error_str is directly from the Slack API endpoint
403 Text/plain
Slack API error (general) Encountered a slack API error: {error_str}
The error_str is directly from the Slack API endpoint
503 Text/plain
Success Slack dm link object (below) 200 Application/JSON

A slack dm link object:

{"statusCode": 200, "slack_dm_link": "url"}

/waiver

Method: POST

Data: JSON

Example JSON:

{
  "email": "users_email@your_hackathon",
  "token": "some hashy boi",
}

Returns

  1. send waiver to s3 by doing a PUT request to the upload url Content-Type header must be set to application/pdf.
  2. get waiver from s3 by doing a GET request to the upload url.
  3. if we have the waiver exists will be true.
{
  "upload": "url",
  "download": "url",
  "exists": true|false,
}
Clone this wiki locally