GithubHelp home page GithubHelp logo

kioui / mentorpunten Goto Github PK

View Code? Open in Web Editor NEW
5.0 2.0 1.0 10.64 MB

Scavenger hunt website for Study Association Thalia

Home Page: https://scavengerhunt.thalia.nu/

License: MIT License

Python 56.58% CSS 3.15% JavaScript 0.49% HTML 3.15% Vue 28.25% TypeScript 7.61% Dockerfile 0.46% Shell 0.32%
django oauth2 oauth2-client oauth2-server scavenger-hunt vuejs vuejs3

mentorpunten's Introduction

Mentorpunten

Welcome to the Mentorpunten repository. This repository includes the application that can be used to set up an online scavenger hunt. The application can be used to create Tournaments and Teams of Users for these Tournaments. Challenges can be created for each Tournament. The Challenges can be solved by the Teams by uploading a photo after which an administrator needs to approve (or decline) a Submission for a Challenge. If a Submission is approved, the Challenge is closed for that Team and points are awarded.

Setup

This project is built using both Django (for the backend) and VueJS (for the frontend). Both need to be set up (and connected) for development to work.

Setup backend

  1. First install at least Python 3.11 on your system.
  2. If pip3 is not installed on your system, execute apt install python3-pip to install it.
  3. Also make sure python3-dev is installed on your system, execute apt install python3-dev.
  4. Install Poetry by following the steps on their website. Make sure poetry is added to PATH before continuing.
  5. Clone this repository.
  6. Go to the backend directory.
  7. Run poetry install to install the backend dependencies.
  8. Run poetry shell to start a shell with the dependencies loaded. This command needs to be run every time you open a new shell and want to run the development server.
  9. Go to the website directory.
  10. Run ./manage.py migrate to initialize the database and load all migrations.
  11. Run ./manage.py createsuperuser to create an administrator user.
  12. Run ./manage.py runserver to start the development server locally.

Now your backend server is setup and running on localhost:8000. The administrator interface can be accessed by going to localhost:8000/admin.

Setup frontend

  1. Install at least version 17 of NodeJS.
  2. Clonse this repository (or if you have done that in the previous steps, skip this step).
  3. Go to the frontend directory.
  4. Use npm install to install the required packages.
  5. Use npm run dev to run the development server.

Connecting the frontend to the backend

Now that both the frontend and the backend server are up and running, we need to supply the frontend with credentials such that it can connect to the backend service.

  1. Log in on the administrator dashboard of the backend by going to localhost:8000/admin and logging in with your administrator account.
  2. Under Django OAuth Toolkit, add an Application.
  3. Provide the following settings:
  1. Before saving the application, make sure to copy over the Client ID and Client Secret to some other location.
  2. Now save the application.
  3. Create a .env file in the frontend folder of the repository. The .env file should have the following content:
VITE_API_BASE_URI=http://localhost:8000
VITE_API_AUTHORIZATION_ENDPOINT=/oauth/authorize/
VITE_API_ACCESS_TOKEN_ENDPOINT=/oauth/token/
VITE_API_OAUTH_CLIENT_ID=[Client ID you copied over]
VITE_API_OAUTH_CLIENT_SECRET=[Client Secret you copied over]
VITE_API_OAUTH_REDIRECT_URI=http://localhost:5173/auth/callback
VITE_API_LOGOUT_URL=/users/logout
VITE_DEBUG=true
  1. Reload the development server (npm run dev) and you are good to go!

Deployment

This project can be deployed by using Docker. For deployment you can follow the following steps. These steps assume that you have a working server that runs Ubuntu which faces the Internet and a domain name pointing to the IP address of the server.

  1. First install Docker by following the steps on their website.
  2. Make sure to also install the Rootless version of Docker.
  3. Run loginctl enable-linger ubuntu to enable the background services for the ubuntu user (such that the container do not stop when you log out of the server).
  4. Run sudo nano /etc/sysctl.conf and add the following line: net.ipv4.ip_unprivileged_port_start=80. This enables privileged ports for the ubuntu user.
  5. Now copy all the contents inside the deployment directory of this repository to a different location.
  6. In the newly copied over deployment directory, create the following directory structure:
data
 | - backend
 |      | - log
 |
 | - database
 |      | - data
 |
 | - shared
 |      | - static
 |      | - media
 |
 | - reverse-proxy
 |      | - conf.d
  1. Also create a repository folder in the deployment directory. Clone this repository inside the repository folder (so the repository should be in repository/mentorpunten).
  2. Create an OAuth application on the Thalia website. The OAuth application should have the following settings:
  • Redirect uris: https://[Your server hostname]/thalia/callback
  • Client type: Confidential
  • Authorization grant type: Authorization code
  • Name: Mentorpunten
  • Skip Authorization: False
  1. Make sure to copy over the Client ID and Client Secret before saving the application. When you are done, save the application.
  2. Now copy over docker-compose.yml.example to docker-compose.yml. Fill the following environment variables:
  • Postgres Password: Create a random password.
  • Django Secret key: Create a random secret key.
  • Mentorpunten hostname: The domain pointing to the server running the deployment.
  • Thalia OAuth Client ID: The Client ID for the Thalia OAuth application from the previous steps.
  • Thalia OAuth Client Secret: The Client Secret for the Thalia OAuth application from the previous steps.
  • Client ID from mentorpunten Django host: Leave empty for now.
  • Client Secret from mentorpunten Django host: Leave empty for now.
  1. Run docker compose build to build both the containers.
  2. Run docker compose pull to pull the nginx and postgres container.
  3. Run docker compose up -d to start the Docker containers.
  4. Run docker exec -it mentorpunten-backend /bin/bash to start a shell in the backend container.
  5. Go to the website directory inside the container by running cd website.
  6. Run ./manage.py collectstatic and ./manage.py createsuperuser to collect static files and create the first administrator user. Exit the shell by running exit.
  7. Now head on over to the Django admin on your domain. You should be able to log in to the admin by using http://[Your domain]/admin-login and the login credentials of the previous step.
  8. Once again create an OAuth application with the following settings:
  • Redirect uris: http://[Your server hostname]/auth/callback
  • Client type: Public
  • Authorization grant type: Implicit
  • Name: VueJS Frontend
  • Skip Authorization: True
  1. Before saving, copy over the Client ID and Client Secret. Now save the OAuth application.
  2. Run docker compose down to stop the containers from running.
  3. Edit the docker-compose.yml file and enter the following variables:
  • Client ID from mentorpunten Django host: The Client ID we got previously.
  • Client Secret from mentorpunten Django host: The Client Secret we got previously.
  1. Run docker compose up -d to start the containers again, the website should now be in working condition.
  2. It might be nice to also enable SSL and HTTPS. You can do this by adding a certbot container to the docker-compose.yml file and enabling port 443 on the reverse-proxy container. Also make sure to edit the nginx config in data/reverse-proxy/conf.d.

Development

This section will explain some of the development steps that you have to take or were taken during development of the application.

Setting environment variables for the frontend

Normally, environment variables are included during build and can not be changed afterwards. This is a problem when building a docker container which can be applied to different scenarios (e.g. with different API servers). Because of this fact, environment variables can be either included during build with a .env file in the root directory or with docker environment variables. Using docker environment variables will overwrite the environment variables included during build.

Environment variables that are available and should be overwritable by docker environment variables later should be included in the docker.blueprint.env file. Note that this file must use ' for indicating strings and the format is as follows:

    '[NAME_OF_VARIABLE_IN_VUE]': '${NAME_OF_ENV_VARIABLE}'

Before starting the nginx process, the docker environment variables will be set under the window.__env__ variable in the index.html file.

Using environment variables for the frontend

To use environment variables that can be set during runtime (with docker environment variables), add the variable to the docker.blueprint.env file as explained above. Then use the getEnvVar function in src/common/general.service.ts for getting the value of an environment variable. This function will first check whether it is set in the window.__env__ variable and will then look if it is an environment variable.

mentorpunten's People

Contributors

dependabot[bot] avatar jendusseljee avatar jobdoesburg avatar kioui avatar nvoers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

svthalia

mentorpunten's Issues

Equal points in tournament

Currently places with equal points are sorted lexicographically, but that should be based on who got that amount of points first

Tournament selector in header

It would be good for UX to implement a tournament selector dropdown in the header.

image

Simply make the title clickable (with a little collapse-triangle icon next to it) and display a dropdown of the tournament. The header should display the name of the tournament

URL paths can be

scavengerhunt.thalia.nu//feed
scavengerhunt.thalia.nu//challenges
scavengerhunt.thalia.nu//store
scavengerhunt.thalia.nu//scoreboard

etc.

Or you can work with cookies for the selected tournament.

Failed to load submissions due to permissions bug

Internal Server Error: /api/v1/challenges/submissions/
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view
    return view_func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/views/generic/base.py", line 104, in view
    return self.dispatch(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/rest_framework/generics.py", line 239, in get
    return self.list(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/rest_framework/mixins.py", line 43, in list
    return self.get_paginated_response(serializer.data)
                                       ^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py", line 768, in data
    ret = super().data
          ^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py", line 253, in data
    self._data = self.to_representation(self.instance)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py", line 686, in to_representation
    return [
           ^
  File "/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py", line 687, in <listcomp>
    self.child.to_representation(item) for item in iterable
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py", line 522, in to_representation
    ret[field.field_name] = field.to_representation(attribute)
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py", line 522, in to_representation
    ret[field.field_name] = field.to_representation(attribute)
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py", line 686, in to_representation
    return [
           ^
  File "/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py", line 687, in <listcomp>
    self.child.to_representation(item) for item in iterable
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py", line 509, in to_representation
    attribute = field.get_attribute(instance)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/rest_framework/fields.py", line 446, in get_attribute
    return get_attribute(instance, self.source_attrs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/rest_framework/fields.py", line 101, in get_attribute
    instance = instance()
               ^^^^^^^^^^
  File "/mentorpunten/src/website/users/models.py", line 78, in get_user_permissions
    return [(x.id, x.name) for x in user.user_permissions.all()] | [
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: unsupported operand type(s) for |: 'list' and 'list'

Lazy load images

Currently, all images are directly loaded when loading the page. For a feed, this is not good practice as it creates a lot of data traffic. Instead, let the browser lazy load the images (only when they are about to appear in the viewport). I think using simply specifying the source as lazy-src does everything

FAQ button

Add a button or link to the faq page somewhere

Create menu

Create a menu with profile, add transactions and logout

Tests for the API

We need tests for the Django API such that we can be sure that no unwanted behaviour can happen.

Import teams

We need to be able to import teams, challenges, etc. such that this process is easy.

Implement option to specify whether leaderboard should be based on total points acquired, or current balance

Maybe I acquire 100 points during a tournament, but in the store I buy things for 80 points.
Should I be displayed in the leader board with 20 points (because I also spent points)? Or should I still be leading with 100 points (because that's still what I earned).

This choice depends on your view on the tournament (whether the store is an actual game element, or a reward store). I think this behavior should be user-selected for each tournament (or store)

Team view is hidden

The UI is not clear that teams are clickable and that they present a whole overview page of a team. This should be improved. Maybe make a team page, accessible from the bottom menu bar

Implement blur-preview when submissions are hidden until you submit yourself

Basically the title, just as with BeReal.

To implement the blur in a proper way (we are computer scientists, so we should do this properly), I propose to use a very low-res thumbnail (less 50px maybe, so you really cannot see what's on it) and apply a CSS3 blur filter to it (to make it look nicer and not pixellated)

Tournament-specific styling

In order to make this product really versatile, I propose to implement tournament-specific styling (after #81 has been implemented).

Don't worry, this is easier than you might think.

Via the admin for every tournament, you can select a theme color and perhaps a font family (and maybe upload a favicon?). These are simply added to the API's tournament serializer and the frontend just applies them. That's it.

Additionally, we could implement a field on tournaments with custom CSS, that we also simply just load. This is exactly done in this way in CTFd and it works perfect

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.