diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..d3cbace --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,5 @@ +# Contributing + +Thank you for help improving Place. All kinds of contributions are welcome. + +Please submit an Issue or even better a PR and We'll review :) diff --git a/Dockerfile b/Dockerfile index fbd13b1..f0e1d5f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM python:3.13-slim-bookworm AS builder COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ # Change the working directory to the `app` directory -WORKDIR /opt +WORKDIR /app # Install dependencies RUN --mount=type=cache,target=/root/.cache/uv \ @@ -11,19 +11,25 @@ RUN --mount=type=cache,target=/root/.cache/uv \ uv sync --frozen --no-install-project --no-editable --no-dev --group prod # Copy the project into the intermediate image -ADD ./place /opt +ADD ./place /app FROM python:3.13-slim-bookworm -WORKDIR /opt - # Copy the environment, but not the source code -COPY --from=builder --chown=opt:opt /opt /opt +COPY --from=builder --chown=app:app /app /app -EXPOSE 8000 +WORKDIR /app # entrypoint, must be executable file chmod +x entrypoint.sh COPY entrypoint.sh . +# Set environment variables +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 +ENV PATH="/app/.venv/bin:$PATH" + +# Expose port 8000 +EXPOSE 8000 + # Run the application ENTRYPOINT ["./entrypoint.sh"] diff --git a/README.md b/README.md index 91e69bc..18c3662 100644 --- a/README.md +++ b/README.md @@ -4,67 +4,107 @@ An event application for Cameroon that helps users find events based on their interests, location, and availability. -## Deployment Guide +## Table of Contents +* **[Installation](#installation)** + * [uv](#uv) + * [Pip](#pip) + * [Docker](#docker) +* [Contributing](#contributing) +* [Support](#support) +* [License](#license) -### Prerequisites +## 📖 Installation -- **Python 3.11+** ([Download](https://python.org)) +Place can be installed via Pip or Docker. To start, clone the repo to your local computer and change into the proper directory. + +### 🧰 Prerequisites + +- **Python 3.13+** ([Download](https://python.org)) - **Docker** (Optional) ([Install Docker](https://docs.docker.com/get-started/get-docker/)) -- **UV** (Optional, for fast Python management) ([Install UV](https://docs.astral.sh/uv/getting-started/installation/)) - -### Setup Instructions - -**Install Dependencies** - - **With Python:** - ```sh - pip install . - ``` - - **With UV (Faster):** No needed - - **With Docker:** No needed - -**Setup** - - **With Python:** - ```sh - python place/manage.py makemigrations - python place/manage.py migrate - ``` - - **With UV (Faster):** - ```sh - uv run place/manage.py makemigrations - uv run place/manage.py migrate - ``` - - **With Docker:** No needed - -**Run the App** - - **With Python:** - ```sh - python place/manage.py runserver - ``` - - **With UV (Faster):** - ```sh - uv run place/manage.py runserver - ``` - - **With Docker:** - ```sh - docker compose up -d - ``` - -**Loading the dummy data** - - **With Python:** - ```sh - python place/manage.py shell -c "import core.dummy_data" - ``` - - **With UV (Faster):** - ```sh - uv run place/manage.py shell -c "import core.dummy_data" - ``` - - **With Docker:** - ```sh - docker compose exec place-web ./entrypoint.sh shell -c \"import core.dummy_data\" - ``` +- **UV** (Optional, for fast Python package management) ([Install UV](https://docs.astral.sh/uv/getting-started/installation/)) + +### Install Dependencies + +- With Pip: + +```sh +pip install . +``` + +- With uv: + +```sh +uv sync +``` + +- With Docker: Not needed + +### Setup + +- With Python: + +```sh +python place/manage.py migrate +``` + +- With uv: + +```sh +uv run place/manage.py migrate +``` + +- With Docker: Not needed + +### Run the App + +- With Python: + +```sh +python place/manage.py runserver +``` + +- With uv: + +```sh +uv run place/manage.py runserver +``` + +- With Docker: + +```sh +docker compose up -d +``` + +### Load the dummy data + +- With Python: + +```sh +python place/manage.py shell -c "import core.dummy_data" +``` + +- With uv: + +```sh +uv run place/manage.py shell -c "import core.dummy_data" +``` + +- With Docker: + +```sh +docker compose exec place ./entrypoint.sh shell -c \"import core.dummy_data\" +``` **Access the webapp** - Open your browser at: [http://127.0.0.1:8000](http://127.0.0.1:8000) + Open your browser at: [http://127.0.0.1:8000](http://127.0.0.1:8000) or [http://127.0.0.1:8000/admin](http://127.0.0.1:8000/admin) for the admin + +## 🤝 Contributing + +Contributions, issues and feature requests are welcome! See [CONTRIBUTING.md](https://github.com/wsvincent/lithium/blob/master/CONTRIBUTING.md). + +## ⭐️ Support + +Give a ⭐️ if this project helped you! ## License diff --git a/docker-compose.yaml b/docker-compose.yaml index d4c9ad5..480062e 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -3,14 +3,14 @@ services: image: place build: . volumes: - - static_data:/opt/staticfiles + - static_data:/app/staticfiles place-nginx: image: nginx:latest volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - - static_data:/opt/staticfiles:ro + - static_data:/app/staticfiles:ro ports: - 8000:80 volumes: - static_data: \ No newline at end of file + static_data: diff --git a/entrypoint.sh b/entrypoint.sh index 56cac1e..e194398 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -9,7 +9,7 @@ set -ex .venv/bin/python manage.py migrate --noinput if [ -z "$@" ]; then - gunicorn place.asgi:application -k uvicorn_worker.UvicornWorker -b 0.0.0.0:8000 + gunicorn place.asgi:application -k uvicorn_worker.UvicornWorker -b :8000 -w 2 else eval .venv/bin/python manage.py $@ -fi \ No newline at end of file +fi diff --git a/place/accounts/__init__.py b/place/accounts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/place/accounts/admin.py b/place/accounts/admin.py new file mode 100644 index 0000000..5cf35f3 --- /dev/null +++ b/place/accounts/admin.py @@ -0,0 +1,20 @@ +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin + +from .forms import CustomUserCreationForm, CustomUserChangeForm +from .models import CustomUser + + +class CustomUserAdmin(UserAdmin): + add_form = CustomUserCreationForm + form = CustomUserChangeForm + model = CustomUser + list_display = [ + "email", + "username", + "is_staff", + "is_active", + ] + + +admin.site.register(CustomUser, CustomUserAdmin) diff --git a/place/accounts/apps.py b/place/accounts/apps.py new file mode 100644 index 0000000..0cb51e6 --- /dev/null +++ b/place/accounts/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class AccountsConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "accounts" diff --git a/place/accounts/forms.py b/place/accounts/forms.py new file mode 100644 index 0000000..bcfe525 --- /dev/null +++ b/place/accounts/forms.py @@ -0,0 +1,20 @@ +from django.contrib.auth.forms import AdminUserCreationForm, UserChangeForm +from .models import CustomUser + + +class CustomUserCreationForm(AdminUserCreationForm): + class Meta: + model = CustomUser + fields = ( + "email", + "username", + ) + + +class CustomUserChangeForm(UserChangeForm): + class Meta: + model = CustomUser + fields = ( + "email", + "username", + ) diff --git a/place/accounts/migrations/__init__.py b/place/accounts/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/place/accounts/models.py b/place/accounts/models.py new file mode 100644 index 0000000..c142283 --- /dev/null +++ b/place/accounts/models.py @@ -0,0 +1,9 @@ +from django.contrib.auth.models import AbstractUser +# from django.db import models + + +class CustomUser(AbstractUser): + pass + + def __str__(self): + return self.email diff --git a/place/accounts/tests.py b/place/accounts/tests.py new file mode 100644 index 0000000..a79ca8b --- /dev/null +++ b/place/accounts/tests.py @@ -0,0 +1,3 @@ +# from django.test import TestCase + +# Create your tests here. diff --git a/place/accounts/views.py b/place/accounts/views.py new file mode 100644 index 0000000..fd0e044 --- /dev/null +++ b/place/accounts/views.py @@ -0,0 +1,3 @@ +# from django.shortcuts import render + +# Create your views here. diff --git a/place/core/models.py b/place/core/models.py index 93bfbc7..62d9112 100644 --- a/place/core/models.py +++ b/place/core/models.py @@ -1,6 +1,5 @@ from django.db import models from django.utils import timezone - from django.shortcuts import reverse diff --git a/place/core/templates/core/event.html b/place/core/templates/core/event.html index 3a1aa45..954e864 100644 --- a/place/core/templates/core/event.html +++ b/place/core/templates/core/event.html @@ -1,7 +1,5 @@
+ {% if event.image %}CSRF verification failed. Request aborted.
+{% endblock content %} diff --git a/place/templates/404.html b/place/templates/404.html new file mode 100644 index 0000000..c6fb64e --- /dev/null +++ b/place/templates/404.html @@ -0,0 +1,5 @@ +{% extends 'base.html' %} +{% block title %}404 Page not found{% endblock %} +{% block content %} +Looks like something went wrong!
+{% endblock content %} diff --git a/place/core/templates/core/_base.html b/place/templates/_base.html similarity index 75% rename from place/core/templates/core/_base.html rename to place/templates/_base.html index ff4791e..2e8848c 100644 --- a/place/core/templates/core/_base.html +++ b/place/templates/_base.html @@ -3,8 +3,16 @@ + -Are you sure you want to sign out?
+ +{% endblock content %} diff --git a/place/templates/account/password_change.html b/place/templates/account/password_change.html new file mode 100644 index 0000000..b3943a8 --- /dev/null +++ b/place/templates/account/password_change.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% load crispy_forms_tags %} +{% block title %}Change Password{% endblock %} +{% block content %} +We have sent you an e-mail. Please contact us if you do not receive it in a few minutes.
+{% endblock content %} diff --git a/place/templates/account/password_reset_from_key.html b/place/templates/account/password_reset_from_key.html new file mode 100644 index 0000000..48c68cb --- /dev/null +++ b/place/templates/account/password_reset_from_key.html @@ -0,0 +1,29 @@ +{% extends 'base.html' %} +{% load crispy_forms_tags %} +{% block title %} + Change Password +{% endblock title %} +{% block content %} ++ The password reset link was invalid. Perhaps it has already been used? Please request a new password reset. +
+ {% else %} + {% if form %} + + {% else %} +Your password is now changed.
+ {% endif %} + {% endif %} +{% endblock content %} diff --git a/place/templates/account/password_reset_from_key_done.html b/place/templates/account/password_reset_from_key_done.html new file mode 100644 index 0000000..653748b --- /dev/null +++ b/place/templates/account/password_reset_from_key_done.html @@ -0,0 +1,9 @@ +{% extends 'base.html' %} +{% load crispy_forms_tags %} +{% block title %} + Change Password Done +{% endblock title %} +{% block content %} +Your password has been changed.
+{% endblock content %} diff --git a/place/templates/account/password_set.html b/place/templates/account/password_set.html new file mode 100644 index 0000000..96ba23a --- /dev/null +++ b/place/templates/account/password_set.html @@ -0,0 +1,20 @@ +{% extends 'base.html' %} +{% load crispy_forms_tags %} +{% block title %} + Set Password +{% endblock title %} +{% block content %} + +{% endblock content %} diff --git a/place/templates/account/signup.html b/place/templates/account/signup.html new file mode 100644 index 0000000..6d15899 --- /dev/null +++ b/place/templates/account/signup.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% load crispy_forms_tags %} +{% block title %}Sign up{% endblock %} +{% block content %} +