Event-Fi is an app designed to comfortably create, manage, share and find events, via a single simple app. It utilizes a map layout (using mapbox GL) based on markers for each location/event, in order to have an easy visualization and a user-friendly experience.
Felipe Perez Frontend Developer đź’» Commits |
Diego Merentiel Full Stack Developer đź’» Commits |
Martin Casamayou Backend Developer đź’» Commits |
Santiago Goyret Project Manager & DevOps đź’» Commits |
On an Ubuntu 22.04 based server follow this next steps
-
-
Clone our repository
$ git clone https://github.com/BergeDios/Event-fi.git
-
-
-
Run our Configuration Script to install all dependencies
$ ./config.sh
-
-
- You are done! The app is now running in the background in localhost:8000
You can check the status of the service running
$ sudo systemctl status event-fi.service
. Also all the logs from the app down to debug level, are being redirected to/var/log/gunicorn/stdout
and/var/log/gunicorn/stderr
.
A Ubuntu Server (22.04) running over AWS EC2
Our app has a basic infrastructure consisting of a server instance hosted via the AWS EC2 service. Then with the Nginx web server we reverse proxy our localhost, that is deploying our app via Gunicorn service in the background through the port 8000. We also hold a second instance to the side enabling us to have a blue/green deployment strategy to reduce downtime and facilitate update deployments.
graph LR
A[User enters event-fi.com] -- SSL Certificate<br/>Firewall --> B((AWS EC2))
B --> C(Nginx Web Server)
C -- Reverse proxy<br/>localhost:8000 --> D(Gunicorn in background)
D --> E{Event-Fi App}
E --> A
This web app, though responsive, is mainly focused on mobile usage. [ Desktop usage works as well ]. For this reason, it is highly recommended to be tested in small devices.
HTML documents were designed with Jinja's templates engine. There is a base.html template which contains the main structure of almost every document on the app, this being inherited by the rest of templates. Main structure being:
<div class="wraper" id="wraper">// Where all elements go
<div class="header" id="header">
</div>
<div class="container" id="container">
</div>
</div>
There is a style sheet for each template created, each one sharing characteristics like the color palette used. User experience is focused, with a simple interface. Here you can see for example our User View of the main page in the app showing the events it's invited to, and the User Profile View:
Js is used to request and display dynamic content from or to the API that was made. Visually speaking, it is used to make navigation bars and interactive buttons as well. Script contents are divided into several functions, but no framework or library was used to make modules.
Simpler to explain with a code example, how is that the app handles communicating to its API?
- Firstly, an XMLHTTPRequest object is made; for example, here it is getting information from an event.
var request = new XMLHttpRequest(); request.open('GET','/api/events/' + eventid); request.setRequestHeader('Content-Type', 'application/json'); request.setRequestHeader('Access-Control-Allow-Origin', '*'); request.setRequestHeader('Access-Control-Allow-Headers', '*'); request.send();
- Sends the request and, when that request is loaded and has a response, it parses the information obtained and displays it.
request.onload = function() { var data = JSON.parse(request.responseText); }
The app has an integrated map that is provided by Mapbox GL JS API. Whenever the event is clicked, the user will be redirected to a view which will display a map, giving geological information about the particular location requested.
A more technical example of how the app communicates with the Mapbox API will be the following:
- It authenticates with a token and creates a map into the div that was specifically made to contain it.
const map = new mapboxgl.Map({ container: 'map', style: 'mapbox://styles/mapbox/light-v10', center: [geojson.geometry.coordinates[0], geojson.geometry.coordinates[1]], zoom: 16 });
- As seen, the center is specified with the location of the event.
For the MVP we decided to use Python along with Flask, a lightweight backend framework that allows us to quickly develop and test functionalities for the app as well as adding new endpoints that handle Server Side Rendering, thanks to the usage of the Jinja2 engine creating the needed static html content already loaded with the necessary data. Since the information may vary a lot between each event and location, to store our data we integrated MongoDB to our workflow, based on its document based non-relational schema with great dynamic capabilities.
In order to retrieve data from the different models, the following routes are implemented.
note that you need valid credentials in most of the functionalities. Only "sudo" users have access to every endpoint of the app
/api/users/<user_id>
Returns the information of a given user
/api/users/<user_id>/contacts
Returns a list with all the user contacts
If the contact_id exists in the database, the contact info is added to the user contact list
If the contact_id is found in the user contacts, it is removed from the list.
/api/users/<user_id>/notifications
If checking is True, then it just returns a message signaling that the user has unread notifications. If checking is False, then it returns the user notifications to the front and deletes them.
. /api/groups
Returns a list with all the groups that the current logged user is part of.
Adds a new group and sets the creator as owner and admin
/api/groups/<group_id>
Returns the information of a given group (name, avatar, members and events)
Sends new form to update the group info
Removes the group from all the relations and then deletes it from the database.
/api/groups/<group_id>/members
Returns a list with all the members of a group.
If the user exists, it is added to the group members with its type if it is specified.
Updates the type of a group member, in order to give or remove admin privileges.
Removes a member from the group.
/api/events
Returns a list of all the upcoming events for the current logged user. If the filter is specified with a date, then it will only show the events for that particular day.
Adds a new event setting the creator as owner and admin, also gives the possibility to invite groups or specific users in the creation form.
/api/events/<event_id>
Returns the information of a given event (name, avatar, start_date, end_date, location, groups, members)
Updates the information of the event through a form.
Removes the event from all the collections it is related to and then deletes it from the database.
/api/events/<event_id>/members
Returns a list with the information of all the members of a given event.
Adds a new member to the event with a member type if specified.
Updates the type of a given member, used for managing admin privileges.
Removes a member from the event.
/api/events/<event_id>/groups
Returns a list with the information of all the groups of a given event.
Adds all the members from the group to the event member list and also the group itself to the event group list.
Removes all the group members and the group itself from the event.
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.