Skip to content

Commit

Permalink
Merge pull request #292 from jwjacobson/tags
Browse files Browse the repository at this point in the history
Tags
  • Loading branch information
jwjacobson authored Sep 13, 2024
2 parents 4c21018 + 635cefc commit 2647b7d
Show file tree
Hide file tree
Showing 12 changed files with 227 additions and 44 deletions.
56 changes: 56 additions & 0 deletions .github/workflows/django.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: jazztunes CI and Deployment

on:
push:
branches: [ "main" ]

jobs:
build-and-deploy:
environment: jazztunes
runs-on: ubuntu-latest
strategy:
max-parallel: 4
matrix:
python-version: [3.11, 3.12]

# Define service containers for running tests
services:
postgres:
image: postgres
env:
POSTGRES_USER: testuser
POSTGRES_PASSWORD: testpass
POSTGRES_DB: testdb
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run Tests
env:
DATABASE_URL: postgres://testuser:testpass@localhost:5432/testdb
ADMIN_USER_ID: ${{ secrets.ADMIN_USER_ID }}
ALLOWED_HOSTS: ${{ secrets.ALLOWED_HOSTS }}
SECRET_KEY: ${{ secrets.SECRET_KEY }}

run: |
pytest
- name: Deploy to Heroku
env:
HEROKU_API_KEY: ${{ secrets.HEROKU_API_KEY }}
run: |
git fetch --unshallow || true
git push https://heroku:[email protected]/${{ secrets.HEROKU_APP_NAME }}.git HEAD:main -f
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ This readme focuses on technical aspects of the app of interest to developers; f
Jazztunes uses [Django 5.0](https://www.djangoproject.com/) on the back end and [htmx](https://htmx.org/) on the front end with [Bootstrap](https://getbootstrap.com/) for styling. The database is [PostgreSQL](https://www.postgresql.org/). It uses [DataTables](https://datatables.net/) for column sorting. Tests are written in [pytest](https://docs.pytest.org/en/8.2.x/). It runs on Python 3.11 or later.

### Local installation
If you want to run jazztunes locally, follow the following steps:
If you want to run jazztunes locally, take the following steps:
1. Clone this repository.
2. Navigate to the 'jazztunes' directory.
3. Create a virtual environment ```python -m venv venv''' (Windows/Linux) or ```python3 -m venv venv``` (Mac).
4. Activate the virtual environment ```.\venv\Scripts\activate``` (Windows) or ```source venv/bin/activate```
5. Install the necessary packages: ```pip install -r requirements.txt```
6. Run the program: ```python manage.py runserver ```
7. Ctrl-click on ```http://127.0.0.1:8000``` — This will open jazztunes in your default browser.
8. You can close the program by closing your browser and pressing Ctrl-C in the terminal running it.
6. Create a .env file in the root directory with the variables (I've supplied a file, env-template, that shows what you need and has some default values)
7. If you want to use the Public tune feature, you'll need to create a superuser: ```python manage.py createsuperuser```, then set that user's ID to ADMIN_USER_ID in .env (it will be 1 if it's the first user created, otherwise 2, etc.). Then tunes you create as that user will also show up on the Public page. Creating a superuser is also a good idea because it gives you access to the [Django admin](https://docs.djangoproject.com/en/5.0/ref/contrib/admin/) interface.
8. Run the program: ```python manage.py runserver ```
9. Ctrl-click on ```http://127.0.0.1:8000``` — This will open jazztunes in your default browser.
10. You can close the program by closing your browser and pressing Ctrl-C in the terminal running it.

### License
Jazztunes is [free software](https://www.fsf.org/about/what-is-free-software), released under version 3.0 of the GPL. Everyone has the right to use, modify, and distribute jazztunes subject to the [stipulations](https://github.com/jwjacobson/jazztunes/blob/main/LICENSE) of that license.
16 changes: 16 additions & 0 deletions env-template
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
This file contains the environment variables you'll need to set in .env for the app to run.
I've supplied some default values that might work well.
"""
# The following are required:
DATABASE_URL=sqlite:///db.sqlite3
ADMIN_USER_ID=1
SECRET_KEY='whatever'
DEBUG=True
ALLOWED_HOSTS=127.0.0.1

# These are optional:
SENTRY_DSN=
SENDGRID_API_KEY=
DEFAULT_FROM_EMAIL=
PYTHONBREAKPOINT=ipdb.set_trace
10 changes: 5 additions & 5 deletions tune/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@


from django.contrib import admin
from tune.models import Tune, RepertoireTune
from tune.models import Tune, RepertoireTune, Tag


@admin.register(Tune)
Expand All @@ -34,7 +34,7 @@ class RepertoireTuneAdmin(admin.ModelAdmin):
autocomplete_fields = ("tune", "player")


# @admin.register(Tag)
# class TagAdmin(admin.ModelAdmin):
# list_display = ["name"]
# search_fields = ("name",)
@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
list_display = ["name"]
search_fields = ("name",)
20 changes: 9 additions & 11 deletions tune/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,6 @@ def clean_other_keys(self):
data = " ".join(formatted_data)
return data

# def clean_tags(self):
# data = self.cleaned_data["tags"]
# if data is None:
# return data
# formatted_data = []
# for tag in data.split():
# formatted_data.append(tag.lower())
# data = " ".join(formatted_data)
# return data


class DateInput(forms.DateInput):
input_type = "date"
Expand All @@ -91,13 +81,21 @@ class RepertoireTuneForm(ModelForm):
class Meta:
model = RepertoireTune
exclude = ["tune", "player", "started_learning", "play_count"]
widgets = {"last_played": DateInput()}
widgets = {"last_played": DateInput(), "tags": forms.SelectMultiple()}

def __init__(self, *args, **kwargs):
super(RepertoireTuneForm, self).__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].widget.attrs["class"] = "form-control"

def save(self, commit=True):
instance = super(RepertoireTuneForm, self).save(commit=False)
if commit:
instance.save()
self.save_m2m()
# breakpoint()
return instance


class SearchForm(forms.Form):
TIMES = [
Expand Down
34 changes: 34 additions & 0 deletions tune/migrations/0005_tag_repertoiretune_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Generated by Django 5.0.4 on 2024-06-22 20:54

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("tune", "0004_alter_repertoiretune_last_played"),
]

operations = [
migrations.CreateModel(
name="Tag",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=20, unique=True)),
],
),
migrations.AddField(
model_name="repertoiretune",
name="tags",
field=models.ManyToManyField(
related_name="repertoire_tunes", to="tune.tag"
),
),
]
19 changes: 19 additions & 0 deletions tune/migrations/0006_alter_repertoiretune_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 5.0.4 on 2024-06-26 17:38

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("tune", "0005_tag_repertoiretune_tags"),
]

operations = [
migrations.AlterField(
model_name="repertoiretune",
name="tags",
field=models.ManyToManyField(
blank=True, related_name="repertoire_tunes", to="tune.tag"
),
),
]
22 changes: 22 additions & 0 deletions tune/migrations/0007_alter_repertoiretune_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 5.0.4 on 2024-06-26 17:52

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("tune", "0006_alter_repertoiretune_tags"),
]

operations = [
migrations.AlterField(
model_name="repertoiretune",
name="tags",
field=models.ManyToManyField(
blank=True,
help_text="ctrl-click to select more than one",
related_name="repertoire_tunes",
to="tune.tag",
),
),
]
17 changes: 9 additions & 8 deletions tune/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,6 @@
from django.contrib.auth import get_user_model


# class Tag(models.Model):
# name = models.CharField(max_length=20)

# def __str__(self):
# return self.name


class Tune(models.Model):
"""
The Tune is the heart of this app; each tune is one song that can be added to a user's repertoire and should contain all relevant musical information.
Expand Down Expand Up @@ -147,6 +140,9 @@ def __str__(self):
class Tag(models.Model):
name = models.CharField(max_length=20, unique=True)

def __str__(self):
return self.name


class RepertoireTune(models.Model):
"""
Expand All @@ -169,7 +165,12 @@ class RepertoireTune(models.Model):
)
started_learning = models.DateTimeField(blank=True, null=True)
play_count = models.IntegerField(default=0)
tags = models.ManyToManyField(Tag, related_name="repertoire_tunes")
tags = models.ManyToManyField(
Tag,
related_name="repertoire_tunes",
blank=True,
help_text="ctrl-click to select more than one",
)

class Meta:
unique_together = ("tune", "player")
Expand Down
8 changes: 7 additions & 1 deletion tune/templates/tune/form.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ <h2 class="text-info-emphasis">{% if tune %}Edit{% else %}New{% endif %} Tune</h
<!-- </div>
</div> -->
</div>
<div class="col-md-6"></div>
<!-- <div class="col-md-6"></div> -->
</div>
<form method="post">
<div class="row">
Expand All @@ -40,8 +40,14 @@ <h2 class="text-info-emphasis">{% if tune %}Edit{% else %}New{% endif %} Tune</h
<p>{{ field.label_tag }}</p>
{{ field }}
{{ field.errors }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</p>
</div>
{% if forloop.counter|divisibleby:2 %}
<div class="col-md-6"></div>
{% endif %}
{% endfor %}
<div class="col-md-6"></div>
<div class="col-md-6 my-3">
Expand Down
12 changes: 8 additions & 4 deletions tune/templates/tune/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ <h4>
<th>Style</th>
<th>Meter</th>
<th>Year</th>
<!-- <th>Tags</th> -->
<th>Tags</th>
<th>Knowledge</th>
<th>Last played</th>
<th>Actions</th>
Expand All @@ -84,9 +84,13 @@ <h4>
<td>{{ tune.tune.other_keys }}</td>
<td>{{ tune.tune.song_form }}</td>
<td>{{ tune.tune.style }}</td>
<td>{{ tune.tune.meter }}</td>
<td>{{ tune.tune.year }}</td>
<!-- <td>{{ tune.tune.tags.name }}</td> -->
<td>{{ tune.tune.meter|default_if_none:"" }}</td>
<td>{{ tune.tune.year|default_if_none:"" }}</td>
<td>
{% for tag in tune.tags.all %}
<div>{{ tag.name }}</div>
{% endfor %}
</td>
<td>{{ tune.knowledge }}</td>
<td id="last-played-{{ tune.id }}">{{ tune.last_played|date:"MONTH_DAY_FORMAT"}}</td>

Expand Down
Loading

0 comments on commit 2647b7d

Please sign in to comment.