Skip to content

Commit

Permalink
chore: add documentation in README
Browse files Browse the repository at this point in the history
  • Loading branch information
vugonz committed Nov 14, 2024
1 parent ce1fa64 commit 9238c16
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 78 deletions.
18 changes: 9 additions & 9 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Please provided relative paths with ./ or things can break :)

export SESSION_DIR="./data/flask_sessions/"
export SESSION_LIFETIME="3600"
SESSION_DIR="./data/flask_sessions/"
SESSION_LIFETIME="3600"

export DATABASE_PATH="./data/hackerschool.sqlite3"
export ROLES_PATH="./data/roles.json"
export PHOTOS_DIR="./data/photos/"
DATABASE_PATH="./data/hackerschool.sqlite3"
ROLES_PATH="./data/roles.json"
PHOTOS_DIR="./data/photos/"

export LOG_LEVEL="INFO"
export LOGS_PATH="./data/logs/app.log"
LOG_LEVEL="INFO"
LOGS_PATH="./data/logs/app.log"

export ADMIN_USERNAME="admin"
export ADMIN_PASSWORD="admin"
ADMIN_USERNAME="admin"
ADMIN_PASSWORD="admin"
2 changes: 1 addition & 1 deletion .github/workflows/unittests.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

name: Python application
name: Unittests

on:
push:
Expand Down
251 changes: 183 additions & 68 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,93 +1,208 @@
# HS-API
![unittests](https://github.com/HackerSchool/HS-API/actions/workflows/unittests.yml/badge.svg)

## Intro
The HackerSchool API is an integrated database that accepts requests from the Internet via the Flask framework. Its purpose is to ease the resource management process for development teams and Human Resources. This system allows the retrieval member data, their projects, contributions, and other HackerSchool assets.
***
The HackerSchool API is an integrated database that accepts requests from the Internet via the Flask framework. Its purpose is to ease the resource management process for development teams and Human Resources.

## Running
Before you can use the container, you'll need to set up the SQLite database and create some directories. If you already have all application-related directories created and `.env` properly set up, you can skip to Step 2.
---

## Table of Contents

- [Features](#features)
- [Technologies](#extensions)
- [Setup](#setup)
- [Environment Variables](#environment-variables)
- [Project Structure](#project-structure)
- [Testing](#testing)
- [Endpoints](#endpoints)
- [Issues and To-do](#issues-and-to-do)
- [Other](#other)

## Features

- User authentication and role based authorization
- CRUD operations for members and projects
- Members and projects photos fetch and upload

### Step 1
You'll need Flask to create the database and related storage directories that will be mounted onto the container.
Adjust and source the `.env` to specify where you want to store application data on your host, and to include the admin user credentials (if you don't you won't have access to any endpoint, you can create a new user later and delete the admin one).
```sh
## Technologies
- Web App Framework - [Flask](https://github.com/pallets/flask)
- Session management - [Flask-Session](https://github.com/pallets-eco/flask-session/)
- ORM - [Flask-SQLAlchemy](https://github.com/pallets-eco/flask-sqlalchemy/)
- Database - [sqlite3](https://docs.python.org/3/library/sqlite3.html)
<!-- - CORS - [Flask-Cors]() -->

## Setup
### Prerequisites
Make sure you have the following installed:
- Python 3.x
- pip

### Installation
1. **Clone the repository**:
```bash
git clone [email protected]:HackerSchool/HS-API.git
cd HS-API
```
2. **Create a virtual environment**:
```bash
python -m venv .venv
source .venv/bin/activate
source .env
```
3. **Install dependencies**:
```bash
pip install -r requirements.txt
flask db-init
```
4. **Setup environment variables**: Create a `.env` file and add any necessary environment variables (see [Environment Variables](#environment-variables) section).
5. **Setup the database and create an admin user**:
```bash
flask init-db
flask create-admin
```
6. **Run the application**:
```bash
flask run --debug
```

### Step 2
If you are not planning to develop, you can get rid of Flask, you won't need it anymore!
To start the container simply run `docker compose up`.

## Development
For development use the Flask built in development server in a virtual environment. Don't forget to also source `.env` and initiailze the db if necessary on development mode!
```sh
cp .env.example .env
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
flask run --debug
### Docker Setup (Optional)
1. **Create all application-data folders**: `docker compose` will mount the database and required folders into the container. For this you need to initialize the database, please refer to the [installation steps 1 to 5](#installation) to set this up.
1. **Build the docker image**:
```bash
docker compose build
```
2. **Run the application (with gunicorn)**:
```bash
docker compose up
```

## Environment Variables
**TLDR**: You can just `cp .env.example .env` to get all default environment variables ready.

- `SESSION_DIR`: Where to store session files (defaults to `data/flask_sessions/`)
- `SESSION_LIFETIME`: How long a session should last in seconds (defaults to 3 hours)

- `DATABASE_PATH`: Path to the `sqlite3` database file (defaults to `data/hackerschool.sqlite3`)
- `ROLES_PATH`: Path to the roles configuration json file (defaults to `data/roles.json`)
- `PHOTOS_DIR`: Path to the folder where user and project images will be stored (defaults to `data/photos/`)

- `LOG_LEVEL`: Log level (defaults to INFO)
- `LOGS_PATH` Path to logs file (deault to stdout)

These will only be necessary if you'll be using the `flask create-admin` command
- `ADMIN_USERNAME` Admin username
- `ADMIN_PASSWORD` Admin password


**Note**: If you use `docker compose` you will either need the `.env` file or environment variables set (no default values will be used) because `docker compose` will use use them to mount the correct volumes.

## Project Structure
The project follows a layered architecture with a controller, service and models layer.
```txt
+-------------+
| Controller |
+-------------+
^
|
|
+-------------+
| Service |
+-------------+
^ ^
| |
| +---------------------+
| |
+-------------+ +------------------+
| Models | | Other Handlers | (e.g, logos handler in filesystem)
+-------------+ +------------------+
```
The structure is based on the Flask [factory extension pattern](https://flask.palletsprojects.com/en/stable/patterns/appfactories/#factories-extensions).
```txt
├── app/
│ ├── api/ # controller layer
│ │
│ ├── services/ # service layer
│ │
│ ├── models/ # database models layer
│ │
│ ├── commands/ # commands definitions (like init-db, create-admin)
│ │
│ ├── logos/ # logos extension
│ │
│ ├── roles/ # roles extension
│ │
│ ├── config.py # flask configuration variables
│ │
│ ├── extensions.py # loading extensions
│ │
│ └── __init__.py # entrypoint with flask app factory
├── data/ # application files
│ └── roles.json # roles configuration file
└── tests/ # components tests
├── models/
└── roles/
```
---
## Testing
To test run the following in the root directory of the repository:
```bash
python -m unittests -s discover
```

## Endpoints
`Content-Type` refers to the response type for `GET` requests and request type for `POST`, `PUT` and `DELETE` requests.
`-` refers to unused.

### Auth
```txt
Endpoints:
- POST /login Login
- GET /logout Logout
```

| Method | URL | Content-Type | Description |
|----------|---------------|--------------|---------------------------------|
| `POST` | `/login` | `json` | Login and set cookie session ID |
| `GET` | `/logout` | `json` | Logout and end session |

### Members
```txt
Endpoints:
- GET /members Get all members
- POST /members Create member
- GET /members/{username} Get member
- PUT /members/{username} Update member
- DELETE /members/{username} Delete member
- PUT /members/{username}/edit_password Change password
- POST /members/{username}/{proj_name} Add project to member
- DELETE /members/{username}/{proj_name} Remove project from member
- GET /members/{username}/projects Get member projects
- GET /members/{username}/logo Get member logo
- PUT /members/{username}/logo Upload member logo
- DELETE /members/{username}/logo Delete member logo
- GET /members/{username}/roles Get member roles
- PUT /members/{username}/roles Add member roles
- DELETE /members/{username}/roles Delete member roles
```

| Method | URL | Content-Type | Description |
|----------|-----------------------------------------|--------------|-----------------------------------------------------------|
| `GET` | `/members` | `json` | Get a list of all members |
| `POST` | `/members` | `json` | Create a new member |
| `GET` | `/members/{username}` | `json` | Get details of a specific member by username |
| `PUT` | `/members/{username}` | `json` | Update member details by username |
| `DELETE` | `/members/{username}` | `-` | Delete a member by username |
| `PUT` | `/members/{username}/edit_password` | `json` | Change member password by username |
| `POST` | `/members/{username}/{proj_name}` | `json` | Add a project to the member's list |
| `DELETE` | `/members/{username}/{proj_name}` | `-` | Remove a project from the member's list of projects |
| `GET` | `/members/{username}/projects` | `json` | Get a list of all projects a member is associated with |
| `GET` | `/members/{username}/logo` | `-` | Get member's profile logo |
| `PUT` | `/members/{username}/logo` | `multipart/form-data`| Upload or update member's logo |
| `DELETE` | `/members/{username}/logo` | `-` | Delete member's logo |
| `GET` | `/members/{username}/roles` | `json` | Get roles assigned to a member |
| `PUT` | `/members/{username}/roles` | `json` | Add roles to the member |
| `DELETE` | `/members/{username}/roles` | `json` | Remove roles from the member

### Projects
```txt
Endpoints:
- GET /projects Get all projects
- POST /projects Create project
- GET /projects/{proj_name} Get project
- PUT /projects/{proj_name} Update project
- DELETE /projects/{proj_name} Delete project
- POST /projects/{proj_name}/{username} Add project to member
- DELETE /projects/{proj_name}/{username} Remove project from member
- GET /projects/{proj_name}/members Get project members
- GET /projects/{proj_name}/logo Get project logo
- PUT /projects/{proj_name}/logo Upload project logo
- DELETE /projects/{proj_name}/logo Delete project logo
```
### Login
Authentication is session based. To login and start a session, use the `/login` endpoint.

---
## What now?
The next step is creating a frontend.
| Method | URL | Content-Type |Description |
|--------|-------------------------------------------|--------------|-----------------------------------------------------|
| `GET` | `/projects` |`json` | Get a list of all projects |
| `POST` | `/projects` |`json` | Create a new project |
| `GET` | `/projects/{proj_name}` |`json` | Get details of a specific project by project name |
| `PUT` | `/projects/{proj_name}` |`json` | Update project details by project name |
| `DELETE` | `/projects/{proj_name}` |`-` | Delete a project by project name |
| `POST` | `/projects/{proj_name}/{username}` |`json` | Add a member to the project |
| `DELETE` | `/projects/{proj_name}/{username}` |`-` | Remove a member from the project |
| `GET` | `/projects/{proj_name}/members` |`json` | Get a list of all members associated with a project |
| `GET` | `/projects/{proj_name}/logo` |`json` | Get project logo |
| `PUT` | `/projects/{proj_name}/logo` |`multipart/form-data` | Upload or update project logo |
| `DELETE` | `/projects/{proj_name}/logo` |`-` | Delete project logo |

Known issues can be found [here](https://github.com/HackerSchool/HS-API/issues/5), and a TODO list [here](https://github.com/HackerSchool/HS-API/issues/7).
## Issues and To-Do
Known issues can be found [here](https://github.com/HackerSchool/HS-API/issues/5), and a to-do list [here](https://github.com/HackerSchool/HS-API/issues/7).

Contributions are welcomed!
## Other
- A [frontend](https://github.com/HackerSchool/HS-WebApp) application is currently under development.

- A CLI for the API is available [here](https://github.com/HackerSchool/hs-cli).

## CLI
A CLI for the API is available [here](https://github.com/HackerSchool/hs-cli).
Contributions are welcomed!
3 changes: 3 additions & 0 deletions app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
import secrets

from datetime import timedelta
from dotenv import load_dotenv

basedir = os.path.abspath(os.path.dirname(__file__)) + "/.." # the repository folder

load_dotenv(os.path.join(basedir, ".env"))

def _get_env_or_default(env: str, default: str, cast=None):
val = os.environ.get(env, "")
if not val:
Expand Down

0 comments on commit 9238c16

Please sign in to comment.