Name: wappuapp-backend
Owner: Futurice
Description: API for Wappu app client
Created: 2016-03-08 12:28:35.0
Updated: 2018-04-06 10:03:49.0
Pushed: 2018-04-17 09:17:28.0
Size: 687
Language: JavaScript
GitHub Committers
User | Most Recent Commit | # Commits |
---|
Other Committers
User | Most Recent Commit | # Commits |
---|
Dependencies:
Node 4.x or 5.x + npm 2.x
Use NPM 2.x, the current Babel configuration has issues with NPM 3.x and doesn't work ~~properly~~ at all with it
Postgres with PostGis extension
Postgres.app has a built-in support.
Note: The command below has been done already for wappuapp-backend app. It is only useful if you create a new Heroku app.
You can add Postgis support to Heroku Postgres with:
ku pg:psql -a wappuapp-backend
te extension postgis;
Heroku toolbelt
bash ./tools/reset-database.sh
If this doesn't work, you can manually run SQL commands from ./tools/init-database.sql in Postgres console.
cp .env-sample .env && cp .env-test-sample .env-test
Fill in the blanks in .env
and .env-test
files
Ask details from Kimmo Brunfeldt or Tomi Turtiainen.
source .env
or bash .env
Or use autoenv.
npm install
npm install -g knex
knex migrate:latest
Run migrations to local database
knex seed:run
Create seed data to local database
npm start
Start express server locally
Server runs at http://localhost:9000
Start using API endpoints.
Environments:
qa
https://wappuapp-backend-qa.herokuapp.comprod
https://wappuapp-backend.herokuapp.comin/bash
ku addons:create --app wappuapp-backend papertrail
ku addons:create --app wappuapp-backend heroku-postgresql:hobby-dev
ku addons:create --app wappuapp-backend newrelic
Add Postgis:
ku pg:psql -a wappuapp-backend
te extension postgis;
Google Cloud Storage is used for storing images.
Migrations and seeds are automatically run in Heroku when you deploy via git push. Migrations are run if knex detects new files in migrations directory. Seeds must be replayable, they must be upsert operations so they can be run on each push.
Commit changes
Check that tests pass, remember to test migrations locally before push
Take manual backup of postgres
heroku pg:backups capture --app wappuapp-backend
Push changes to production environment:
checkout master
pull
push prod
For testing environments:
You can also release a certain local branch. For example releasing from node
branch to dev: git push dev my-local-branch:master
.
Check that the environment responds and logs(Papertrail) look ok.
Quick test endpoints:
https://wappuapp-backend.herokuapp.com/api/events
https://wappuapp-backend.herokuapp.com/api/feed
https://wappuapp-backend.herokuapp.com/api/action_types
NOTE: Some data is added to the original Excel file via fuzzy match mappings. This was done because initially we did not want to modify the original Excel file itself to prevent csv export and character encoding problems. This is not true anymore but some of the data is still added via fuzzy match mappings. These could be transferred to the xlsx file already.
Download newest .xlsx file containing events (in Drive)
Open it in Excel
Save as -> Windows Comma Separated. Note: use this specifically, not the general csv.
If it asks: press “Save active Sheet” and “Continue”
Run parse script:
tools/parse-events-csv.js ~/Downloads/wapputapahtumat.csv > data/events.json
Make sure events.json looks fine
Push newest code to remote, the events are directly read from JSON file
Download the map markers spreadsheet as CSV
Run parse script:
tools/parse-markers-csv.js ~/Downloads/markers.csv > data/markers.json
Make sure markers.json looks fine
Delete existing map markers from remote Postgres
Push new code to production, knex seeds will update the markers to database
TE users SET is_banned = true WHERE uuid='D47DA01C-51BB-4F96-90B6-D64B77225EB7';
READ THIS:
Always use content-type: application/json
header when doing POST, PUT, PATCH requests
All data is transferred in JSON format
Even images are transferred as base64 strings in JSON. Why?
Why not?
Be prepared that some of these endpoints are not documented correctly
Token authentication is required. Token is sent in x-token
header.
GET /api/events
List events
Query parameters:
cityId
Integer. If specified, returns only events in the city with given id.showPast
Boolean. Should events that have ended also be returned. Defaults to false.Responses:
200 OK
List of event objects.GET /api/events/:id
Get event details
Responses:
200 OK
Body is one of event object with an array of images that are image feed objects.404 Not Found
Event not foundGET /api/teams
List all teams
Query parameters:
city
Integer. If specified, returns only teams based in the city with given id.Responses:
200 OK
List of team objects.POST /api/actions
Create a new action
Query parameters:
cityId
Integer. If specified, generated feed item show in this city's feed. Does nothing when checking into event.Body is one of action objects.
Responses:
200 OK
404
No such city id or on CHECK_IN_EVENT; no such event id.403
On CHECK_IN_EVENT; off time, off site or duplicate check in attempt.PUT /api/vote
Vote on an feed item
Body is one of vote object.
Responses:
200 OK
404 Not found
Feed item not foundGET /api/users
Get user details
Query parameters:
userId
Integer. Required. User to whose details fetchedResponses:
200 OK
Body is one of user details object.404 Not Found
User not foundPUT /api/users/:uuid
Create or update a user
Body is one of user object.
Responses:
200 OK
GET /api/users/:uuid
Get user details
Responses:
200 OK
Body is one of user object.404 Not Found
User not foundGET /api/action_types
List action types available
Body is one of action type object.
Responses:
200 OK
GET /api/markers
List map markers
Body is list of marker objects.
Responses:
200 OK
GET /api/cities
List participating cities
Body is list of city objects.
Query parameters:
id
Integer. If specified, returns only cities with the given ID.name
String. If specified, returns only cities with the given name.Responses:
200 OK
GET /api/feed
Get list of feed
Body is one of feed objects.
Query parameters:
beforeId
Return items before this id, can be used for “infinite scroll” in client.limit
Integer. Default: 20. 1-100. If specified, at max this many items are returned.sort
String. Default: 'new'. In which order the result should be returned. One of: 'new', 'hot'.cityId
Integer. If specified, returns only posts by users belonging to guilds based in the city with given id.type
String. If specified, only feed items of that type are returned. One of: 'IMAGE', 'TEXT'.since
String. ISO-8601 format timestamp. If specified, only feed items created after given timestamp are returned. Note: If no time zone is specified, UTC is assumed.offset
Integer. If specified, offsets the returned list by given amount.Examples:
Get 30 newest feed items: GET /api/feed?limit=30
Get top 5-20 images: GET /api/feed?sort=top&limit=15&offset=5&type=IMAGE
Load 20 more feed items: GET /api/feed?beforeId=123&limit=20
Assuming the id of oldest/last feed item client currently has is 123
.
Responses:
200 OK
GET /api/image/:id
Get specific image
Body is one of image objects.
Responses:
200 OK
404 Not found
DELETE /api/feed/:id
Delete item from feed
:id
Is the id of an item in the feed.
GET /api/mood
Get list of day by day mood
Query parameters:
userId
Integer. If specified, returned ratingCity is for the given user.cityId
Integer. If specified, returned ratingCity is for the given city.teamId
Integer. If specified, returned ratingTeam is for the given team.Body is a list of mood objects.
PUT /api/mood
Create or update mood
Body is one of mood objects.
Responses:
200 OK
403 Forbidden
If uuid has not been included in header.GET /api/radio
Get list of radio stations.
Query parameters:
cityId
String. If specified, returns only stations active in the given city.Responses:
200 OK
Body is list of radio objects.GET /api/radio/:id
Get one of radio stations.
Responses:
200 OK
Body is one of radio objects.
d": 121,
ame": "Spinnin iltapäiväkertho",
ocationName": "Spinnin kerhohuone SA014",
tartTime": "2017-02-21T10:00:00.000Z",
ndTime": "2017-04-21T15:00:00.000Z",
escription": "Raining and freezing outside? Studying terrifies and starting to miss kindergarden times? Spinni solves your problems!\r\r\r\rClimb stairs down to the basement of Sähkötalo and arrive to the club room of Spinni, SA014 on <päivämäärä> starting at 1 PM. Spinni offers some snacks, coloring books (for adults), games, lot of friends to play with - not to mention awesome music and lights. Additionally you may have a look at the regular life of electronic music club that is celebrating its 20th anniversary this year.\r\r\r\rSpinni <3 you",
rganizer": "Spinni",
ontactDetails": "spinni-hallitus@listmail.tut.fi; Valtteri Taimela, valtteri.taimela@student.tut.fi",
eemu": false,
ocation": {
"latitude": 61.450364,
"longitude": 23.858384
overImage": "https://storage.googleapis.com/wappuapp/assets/spinni.jpg",
ity": 3,
bEventId": null,
ttendingCount": 0,
adius": 400,
mages": []
d": 1,
ame": "Tietoteekkarikilta",
mage_path": "foo.com/path_to_image.jpg",
core": "10",
ity": 3
Images is an array of feed objects.
ame": "Hessu Kypärä",
eam": "TiTe",
umSimas": "1",
mages": [
{
"id": "2",
"type": "IMAGE",
"votes": "0",
"userVote": 0,
"hotScore": "195.2537",
"author": {
"id": "1",
"name": "Hessu Kypärä",
"team": "TiTe",
"type": "ME"
},
"createdAt": "2017-04-12T16:40:14.308Z",
"location": {
"latitude": 0.123,
"longitude": 0.123
},
"url": "https://storage.googleapis.com/wappuapp/user_content/123.jpg"
}
User object
{ “uuid”: “de305d54-75b4-431b-adb2-eb6b9e546014”, “name”: “Hessu Kypärä” }
Action type object
{ “id”: “3”, “code”: “CIDER”, “name”: “Grab a cider”, “value”: 10, “cooldown”: 300000 }
Marker object
{ location: {
latitude: -1.2345,
longitude: 56.2322
},
// One of STORE, ALKO, TOILET, TAXI, BAR, RESTAURANT type: “STORE”, title: “K-Supermarket Herkkuduo”,
// Optional url url: “http://www.k-supermarket.fi/” }
Vote object
{ // one of 1, -1 “value”: 1, “feedItemId”: 12 }
City object
{ “id”: 2, “name”: “helsinki” }
Radio object
{ “id”: 2, “name”: “Radiodiodi”, “stream”: null, “website”: null, “cityId”: 2, “nowPlaying”: {
"programTitle": "Mustia kukkia ja kielimoukareita",
"programHost": "Santtu, Jaati, Lari",
"song": null,
"left": 1132504 // How much longer the program is gonna be playing, in ms
} }
Mood objects
GET mood object
{ “date”: “2016-04-15T22:00:00.000Z”, “ratingCity”: “3.3333”, // May be null “ratingTeam”: “5.0000”, // May be null “ratingPersonal”: “10.0000” // May be null }
PUT mood object
{ // Dacimal. Range [0, 10]. Rounded to 4th decimal mark. “rating”: 10, // Optional “description”: “Its friday!”
}
Action objects
Basic action object
e` is one of `SIMA`, `CHECK_IN_EVENT`.
{ // required when event type 'CHECK_IN_EVENT' location: {
latitude: -1.2345,
longitude: 56.2322
}, type: “SIMA”, team: 1, user: 'UUID', // required when event type 'CHECK_IN_EVENT' eventId: 1 }
Image action object
{ location: {
latitude: -1.2345,
longitude: 56.2322
}, type: “IMAGE”, team: 1, imageData: 'base64encodedimage', user: 'UUID' }
Feed objects
Image feed object
{ id: 1, // location is optional so it might be not provided location: {
latitude: -1.2345,
longitude: 56.2322
}, type: “IMAGE”, createdAt: “2016-04-20T09:00:00.000Z”, votes: 10, hotScore: 178.0032, author: {
name: "Nahkasimo",
team: "Sähkökilta",
// Can be 'ME', 'OTHER_USER', 'SYSTEM'
type: "ME"
}, url: “https://storage.googleapis.com/wappuapp/user_content/123.jpg” }
Image objects
{ createdAt: “2016-04-20T09:00:00.000Z”, votes: 10, hotScore: 178.0032, author: {
name: "Nahkasimo",
team: "Sähkökilta",
}, url: “https://storage.googleapis.com/wappuapp/user_content/123.jpg” }
Text feed object
{ id: 1, // location is optional so it might be not provided location: {
latitude: -1.2345,
longitude: 56.2322
}, type: “TEXT”, createdAt: “2016-04-20T09:00:00.000Z”, votes: 10, // If and how the user has voted. One of [-1, 0, 1]. userVote: 0, hotScore: 178.0021, author: {
name: "Nahkasimo",
team: "Sähkökilta",
// Can be 'ME', 'OTHER_USER', 'SYSTEM'
type: "ME"
}, text: “Joujou” }
rror handling
HTTP status code is 400 or higher, response is in format:
{ “error”: “Internal Server Error” }
===
cknowledgements
project is a grateful recipient of the [Futurice Open Source sponsorship program](http://futurice.com/blog/sponsoring-free-time-open-source-activities). ?