Compare commits
	
		
			3 Commits
		
	
	
		
			1.0.0
			...
			7d6b53cd1d
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						7d6b53cd1d
	
				 | 
					
					
						|||
| 
						
						
							
						
						274520c57a
	
				 | 
					
					
						|||
| 
						
						
							
						
						458ee11a71
	
				 | 
					
					
						
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -5,4 +5,4 @@ __pycache__
 | 
				
			|||||||
node_modules
 | 
					node_modules
 | 
				
			||||||
package-lock.json
 | 
					package-lock.json
 | 
				
			||||||
db.sqlite3
 | 
					db.sqlite3
 | 
				
			||||||
static
 | 
					src/timetracker/static
 | 
				
			||||||
@ -1,11 +1,3 @@
 | 
				
			|||||||
## 1.0.0 / 2023-01-20 19:54+01:00
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
* Breaking
 | 
					 | 
				
			||||||
  * Due to major re-arranging and re-naming of the folder structure, tables also had to be renamed.
 | 
					 | 
				
			||||||
* Fixed
 | 
					 | 
				
			||||||
  * Sort form fields alphabetically (https://git.kucharczyk.xyz/lukas/timetracker/issues/39, https://git.kucharczyk.xyz/lukas/timetracker/issues/40)
 | 
					 | 
				
			||||||
  * Start session button starts different game than it says (#44)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## 0.2.5 / 2023-01-18 17:01+01:00
 | 
					## 0.2.5 / 2023-01-18 17:01+01:00
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* New
 | 
					* New
 | 
				
			||||||
 | 
				
			|||||||
@ -5,10 +5,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
:8000 {
 | 
					:8000 {
 | 
				
			||||||
    handle_path /static/* {
 | 
					    handle_path /static/* {
 | 
				
			||||||
        root * /usr/share/caddy
 | 
					        root * src/timetracker/static/
 | 
				
			||||||
        file_server
 | 
					        file_server
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    handle {
 | 
					    handle {
 | 
				
			||||||
        reverse_proxy backend:8001
 | 
					        reverse_proxy :8001
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										13
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								Dockerfile
									
									
									
									
									
								
							@ -2,11 +2,11 @@ FROM node as css
 | 
				
			|||||||
WORKDIR /app
 | 
					WORKDIR /app
 | 
				
			||||||
COPY . /app
 | 
					COPY . /app
 | 
				
			||||||
RUN npm install && \
 | 
					RUN npm install && \
 | 
				
			||||||
    npx tailwindcss -i ./common/input.css -o ./static/base.css --minify
 | 
					    npx tailwindcss -i ./src/input.css -o ./src/timetracker/games/static/base.css --minify
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM python:3.10.9-slim-bullseye
 | 
					FROM python:3.10.9-slim-bullseye
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ENV VERSION_NUMBER 1.0.0
 | 
					ENV VERSION_NUMBER 0.2.5
 | 
				
			||||||
ENV PROD 1
 | 
					ENV PROD 1
 | 
				
			||||||
ENV PYTHONUNBUFFERED=1
 | 
					ENV PYTHONUNBUFFERED=1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -15,13 +15,18 @@ RUN apt update && \
 | 
				
			|||||||
    bash \
 | 
					    bash \
 | 
				
			||||||
    vim \
 | 
					    vim \
 | 
				
			||||||
    curl && \
 | 
					    curl && \
 | 
				
			||||||
 | 
					    apt install -y debian-keyring debian-archive-keyring apt-transport-https && \
 | 
				
			||||||
 | 
					    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg && \
 | 
				
			||||||
 | 
					    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list && \
 | 
				
			||||||
 | 
					    apt update && \
 | 
				
			||||||
 | 
					    apt install caddy && \
 | 
				
			||||||
    rm -rf /var/lib/apt/lists/*
 | 
					    rm -rf /var/lib/apt/lists/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN useradd -m --uid 1000 timetracker
 | 
					RUN useradd -m --uid 1000 timetracker
 | 
				
			||||||
WORKDIR /home/timetracker/app
 | 
					WORKDIR /home/timetracker/app
 | 
				
			||||||
COPY . /home/timetracker/app/
 | 
					COPY . /home/timetracker/app/
 | 
				
			||||||
RUN chown -R timetracker:timetracker /home/timetracker/app
 | 
					RUN chown -R timetracker:timetracker /home/timetracker/app
 | 
				
			||||||
COPY --from=css ./app/static/base.css /home/timetracker/app/static/base.css
 | 
					COPY --from=css /app/src/timetracker/games/static/base.css /home/timetracker/app/src/timetracker/games/static/base.css
 | 
				
			||||||
COPY entrypoint.sh /
 | 
					COPY entrypoint.sh /
 | 
				
			||||||
RUN chmod +x /entrypoint.sh
 | 
					RUN chmod +x /entrypoint.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -31,4 +36,4 @@ RUN pip install --no-cache-dir poetry
 | 
				
			|||||||
RUN poetry install --without dev
 | 
					RUN poetry install --without dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXPOSE 8000
 | 
					EXPOSE 8000
 | 
				
			||||||
CMD [ "/entrypoint.sh" ]
 | 
					ENTRYPOINT [ "/entrypoint.sh" ]
 | 
				
			||||||
							
								
								
									
										3
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Makefile
									
									
									
									
									
								
							@ -34,9 +34,6 @@ dumpgames:
 | 
				
			|||||||
loadplatforms:
 | 
					loadplatforms:
 | 
				
			||||||
	poetry run python manage.py loaddata platforms.yaml
 | 
						poetry run python manage.py loaddata platforms.yaml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
loadall:
 | 
					 | 
				
			||||||
	poetry run python manage.py loaddata data.yaml
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
loadsample:
 | 
					loadsample:
 | 
				
			||||||
	poetry run python manage.py loaddata sample.yaml
 | 
						poetry run python manage.py loaddata sample.yaml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,17 +0,0 @@
 | 
				
			|||||||
---
 | 
					 | 
				
			||||||
services:
 | 
					 | 
				
			||||||
  timetracker:
 | 
					 | 
				
			||||||
    image: registry.kucharczyk.xyz/timetracker
 | 
					 | 
				
			||||||
    build:
 | 
					 | 
				
			||||||
      context: .
 | 
					 | 
				
			||||||
      dockerfile: Dockerfile
 | 
					 | 
				
			||||||
    container_name: timetracker
 | 
					 | 
				
			||||||
    environment:
 | 
					 | 
				
			||||||
      - TZ=Europe/Prague
 | 
					 | 
				
			||||||
      - CSRF_TRUSTED_ORIGINS="https://tracker.kucharczyk.xyz"
 | 
					 | 
				
			||||||
    user: "1000"
 | 
					 | 
				
			||||||
    # volumes:
 | 
					 | 
				
			||||||
    #   - "db:/home/timetracker/app/src/timetracker/db.sqlite3"
 | 
					 | 
				
			||||||
    ports:
 | 
					 | 
				
			||||||
      - "8000:8000"
 | 
					 | 
				
			||||||
    restart: unless-stopped
 | 
					 | 
				
			||||||
@ -1,28 +1,17 @@
 | 
				
			|||||||
---
 | 
					---
 | 
				
			||||||
services:
 | 
					services:
 | 
				
			||||||
  backend:
 | 
					  timetracker:
 | 
				
			||||||
    image: registry.kucharczyk.xyz/timetracker
 | 
					    image: registry.kucharczyk.xyz/timetracker
 | 
				
			||||||
    build:
 | 
					    build:
 | 
				
			||||||
      context: .
 | 
					      context: .
 | 
				
			||||||
      dockerfile: Dockerfile
 | 
					      dockerfile: Dockerfile
 | 
				
			||||||
 | 
					    container_name: timetracker
 | 
				
			||||||
    environment:
 | 
					    environment:
 | 
				
			||||||
      - TZ=Europe/Prague
 | 
					      - TZ=Europe/Prague
 | 
				
			||||||
      - CSRF_TRUSTED_ORIGINS="https://tracker.kucharczyk.xyz"
 | 
					      - CSRF_TRUSTED_ORIGINS="https://tracker.kucharczyk.xyz"
 | 
				
			||||||
    user: "1000"
 | 
					    user: "1000"
 | 
				
			||||||
    volumes:
 | 
					    # volumes:
 | 
				
			||||||
      - "static-files:/home/timetracker/app/static"
 | 
					    #   - "db:/home/timetracker/app/src/timetracker/db.sqlite3"
 | 
				
			||||||
    restart: unless-stopped
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  frontend:
 | 
					 | 
				
			||||||
    image: caddy
 | 
					 | 
				
			||||||
    volumes:
 | 
					 | 
				
			||||||
      - "static-files:/usr/share/caddy"
 | 
					 | 
				
			||||||
      - "$PWD/Caddyfile:/etc/caddy/Caddyfile"
 | 
					 | 
				
			||||||
    ports:
 | 
					    ports:
 | 
				
			||||||
      - "8000:8000"
 | 
					      - "8000:8000"
 | 
				
			||||||
    depends_on:
 | 
					    restart: unless-stopped
 | 
				
			||||||
      - backend
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
volumes:
 | 
					 | 
				
			||||||
  static-files:
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -2,10 +2,12 @@
 | 
				
			|||||||
# Apply database migrations
 | 
					# Apply database migrations
 | 
				
			||||||
set -euo pipefail
 | 
					set -euo pipefail
 | 
				
			||||||
echo "Apply database migrations"
 | 
					echo "Apply database migrations"
 | 
				
			||||||
poetry run python manage.py migrate
 | 
					poetry run python src/timetracker/manage.py migrate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo "Collect static files"
 | 
					echo "Collect static files"
 | 
				
			||||||
poetry run python manage.py collectstatic --clear --no-input
 | 
					poetry run python src/timetracker/manage.py collectstatic --clear --no-input
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo "Starting app"
 | 
					echo "Starting server"
 | 
				
			||||||
poetry run python -m gunicorn --bind 0.0.0.0:8001 timetracker.asgi:application -k uvicorn.workers.UvicornWorker --access-logfile - --error-logfile -
 | 
					caddy start
 | 
				
			||||||
 | 
					cd src/timetracker || exit
 | 
				
			||||||
 | 
					poetry run python -m gunicorn --bind 0.0.0.0:8001 root.asgi:application -k uvicorn.workers.UvicornWorker --access-logfile - --error-logfile -
 | 
				
			||||||
 | 
				
			|||||||
@ -4,8 +4,6 @@ from games.models import Game, Platform, Purchase, Session
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SessionForm(forms.ModelForm):
 | 
					class SessionForm(forms.ModelForm):
 | 
				
			||||||
    purchase = forms.ModelChoiceField(queryset=Purchase.objects.order_by("game__name"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = Session
 | 
					        model = Session
 | 
				
			||||||
        fields = [
 | 
					        fields = [
 | 
				
			||||||
@ -18,9 +16,6 @@ class SessionForm(forms.ModelForm):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PurchaseForm(forms.ModelForm):
 | 
					class PurchaseForm(forms.ModelForm):
 | 
				
			||||||
    game = forms.ModelChoiceField(queryset=Game.objects.order_by("name"))
 | 
					 | 
				
			||||||
    platform = forms.ModelChoiceField(queryset=Platform.objects.order_by("name"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = Purchase
 | 
					        model = Purchase
 | 
				
			||||||
        fields = ["game", "platform", "date_purchased", "date_refunded"]
 | 
					        fields = ["game", "platform", "date_purchased", "date_refunded"]
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@
 | 
				
			|||||||
            {% if purchase %}<a class="dark:text-white hover:underline block" href="{% url 'list_sessions_by_game' purchase.game.id %}">See all platforms</a>{% endif %}
 | 
					            {% if purchase %}<a class="dark:text-white hover:underline block" href="{% url 'list_sessions_by_game' purchase.game.id %}">See all platforms</a>{% endif %}
 | 
				
			||||||
            {% endif %}
 | 
					            {% endif %}
 | 
				
			||||||
            {% if dataset.count >= 1 %}
 | 
					            {% if dataset.count >= 1 %}
 | 
				
			||||||
            <a class="clear-both" href="{% url 'start_session' last.purchase.id %}">
 | 
					            <a class="clear-both" href="{% url 'start_session' dataset.last.purchase.id %}">
 | 
				
			||||||
                <button type="button" title="Track last tracked" class="mt-10 py-1 px-2 bg-green-600 hover:bg-green-700 focus:ring-green-500 focus:ring-offset-blue-200 text-white transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 rounded-lg ">
 | 
					                <button type="button" title="Track last tracked" class="mt-10 py-1 px-2 bg-green-600 hover:bg-green-700 focus:ring-green-500 focus:ring-offset-blue-200 text-white transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 rounded-lg ">
 | 
				
			||||||
                    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="self-center w-6 h-6 inline">
 | 
					                    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="self-center w-6 h-6 inline">
 | 
				
			||||||
                        <path stroke-linecap="round" stroke-linejoin="round" d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.348a1.125 1.125 0 010 1.971l-11.54 6.347a1.125 1.125 0 01-1.667-.985V5.653z" />
 | 
					                        <path stroke-linecap="round" stroke-linejoin="round" d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.348a1.125 1.125 0 010 1.971l-11.54 6.347a1.125 1.125 0 01-1.667-.985V5.653z" />
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,9 @@ def version_date():
 | 
				
			|||||||
        "%d-%b-%Y %H:%m",
 | 
					        "%d-%b-%Y %H:%m",
 | 
				
			||||||
        time.gmtime(
 | 
					        time.gmtime(
 | 
				
			||||||
            os.path.getmtime(
 | 
					            os.path.getmtime(
 | 
				
			||||||
                os.path.abspath(os.path.join(settings.BASE_DIR, "pyproject.toml"))
 | 
					                os.path.abspath(
 | 
				
			||||||
 | 
					                    os.path.join(settings.BASE_DIR, "..", "..", "pyproject.toml")
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
				
			|||||||
@ -85,7 +85,6 @@ def list_sessions(request, filter="", purchase_id="", platform_id="", game_id=""
 | 
				
			|||||||
    # cannot use dataset[0] here because that might be only partial QuerySet
 | 
					    # cannot use dataset[0] here because that might be only partial QuerySet
 | 
				
			||||||
    context["last"] = Session.objects.all().order_by("timestamp_start").last()
 | 
					    context["last"] = Session.objects.all().order_by("timestamp_start").last()
 | 
				
			||||||
    # charts are always oldest->newest
 | 
					    # charts are always oldest->newest
 | 
				
			||||||
    if Session.objects.count() >= 2:
 | 
					 | 
				
			||||||
    context["chart"] = playtime_over_time_chart(dataset.order_by("timestamp_start"))
 | 
					    context["chart"] = playtime_over_time_chart(dataset.order_by("timestamp_start"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return render(request, "list_sessions.html", context)
 | 
					    return render(request, "list_sessions.html", context)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
[tool.poetry]
 | 
					[tool.poetry]
 | 
				
			||||||
name = "timetracker"
 | 
					name = "timetracker"
 | 
				
			||||||
version = "1.0.0"
 | 
					version = "0.2.5"
 | 
				
			||||||
description = "A simple time tracker."
 | 
					description = "A simple time tracker."
 | 
				
			||||||
authors = ["Lukáš Kucharczyk <lukas@kucharczyk.xyz>"]
 | 
					authors = ["Lukáš Kucharczyk <lukas@kucharczyk.xyz>"]
 | 
				
			||||||
license = "GPL"
 | 
					license = "GPL"
 | 
				
			||||||
@ -31,4 +31,4 @@ requires = ["poetry-core"]
 | 
				
			|||||||
build-backend = "poetry.core.masonry.api"
 | 
					build-backend = "poetry.core.masonry.api"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[tool.poetry.scripts]
 | 
					[tool.poetry.scripts]
 | 
				
			||||||
timetracker-import = "common.import_data:import_from_file"
 | 
					timetracker-import = "timetracker.common.import_data:import_from_file"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
module.exports = {
 | 
					module.exports = {
 | 
				
			||||||
    darkMode: 'class',
 | 
					    darkMode: 'class',
 | 
				
			||||||
    content: ["./**/*.{html,js}"],
 | 
					    content: ["./src/**/*.{html,js}"],
 | 
				
			||||||
    theme: {
 | 
					    theme: {
 | 
				
			||||||
        fontFamily: {
 | 
					        fontFamily: {
 | 
				
			||||||
            sans: ['Inter', 'sans-serif'],
 | 
					            sans: ['Inter', 'sans-serif'],
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@ import os
 | 
				
			|||||||
from pathlib import Path
 | 
					from pathlib import Path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
 | 
					# Build paths inside the project like this: BASE_DIR / 'subdir'.
 | 
				
			||||||
BASE_DIR = Path(__file__).resolve().parent.parent
 | 
					BASE_DIR = Path(__file__).resolve()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Quick-start development settings - unsuitable for production
 | 
					# Quick-start development settings - unsuitable for production
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user