Skip to content

Commit

Permalink
Merge branch 'CodingPirates:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
JakobLibak committed May 26, 2021
2 parents 3f5a248 + 5511cda commit cdf2043
Show file tree
Hide file tree
Showing 40 changed files with 1,325 additions and 98 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/node_modules
47 changes: 46 additions & 1 deletion .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ You are more than welcome to contribute to the system. This guide documents how

- Run `docker-compose run web ./manage.py get_live_data` to download public
data and insert it into your local database.

- To get some dummy members, families, etc. you can use the [factories][factories] to create them.
```bash
docker-compose run web ./manage.py shell
from members.tests.factories import MemberFactory
MemberFactory.create_batch(20)
```
Creates 20 members with associated families, departments, etc.
Note that the data generated by the factories is not entirely consistent
with the real world. For instance each member belongs to their own department.

- To create a super user for the admin interface you can run
`docker-compose run web ./manage.py createsuperuser`
Expand All @@ -42,7 +52,7 @@ You are more than welcome to contribute to the system. This guide documents how
following command in a separate terminal:
```bash
docker-compose run web /bin/dart-sass/sass --watch members/static/members/sass/main.scss members/static/members/css/main.css
docker-compose run web node_modules/.bin/sass --watch members/static/members/sass/main.scss members/static/members/css/main.css
```
It will compile SASS when you save a file.
Expand All @@ -63,6 +73,39 @@ You are more than welcome to contribute to the system. This guide documents how
contains a test api key. Quickpay has a series of cards that can be used
[for testing][quickpay_cards]
### Local development
Pragmatic development is to use docker for database and run server and/or tests locally
* Install Poetry
* Install python dependencies: `poetry install`
* Install npm
* Install npm dependencies: `npm install`
* Copy the sample environment file: `cp .env.example .env`
* boot the database with `docker-compose start database`
* boot a selenium docker with `docker run -it -p 4444:4444 -p 7900:7900 --network="host" -v /dev/shm:/dev/shm selenium/standalone-chrome`
* start the virtual env shell and work from there further on with `poetry shell`
* Run sass: `./node_modules/.bin/sass members/static/members/sass/main.scss`
* Run collectstatic: `./manage.py collectstatic --no-input --clear`
* Run the tests: `./manage.py test`
From here on you can boot a development server and optionally populate it with some arbitrary data:
* Boot development server : ``
You can load some sample data into the local development environment by starting the django console with `./manage.py shell` and then
```python
from members.tests.factories.member_factory import MemberFactory
MemberFactory.create_batch(20)
```
In the same console you can create a password for the first person, so you can login:
```python
from members.models import Person
p = Person.objects.first()
p.user.set_password('test')
p.user.save() # store in DB
p.user.username # show login email
```
## Creating a pull request
1. Join our [slack][slackinvite] and introduce yourself in the _medlemssystem_dev_ channel.
Expand Down Expand Up @@ -101,6 +144,8 @@ You are more than welcome to contribute to the system. This guide documents how
[sass]: https://sass-lang.com
[factories]: ./members/tests/factories
[slackinvite]: https://slackinvite.codingpirates.dk
[12f]: https://12factor.net
Expand Down
11 changes: 0 additions & 11 deletions .github/dependabot.yml

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ members/static/members/css
.sass-cache/
public_data.zip
test-screens
/node_modules
22 changes: 16 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
FROM python:3.8
WORKDIR /app

RUN apt-get update && \
apt-get install -y graphviz

RUN wget -O /tmp/sass.tar.gz https://github.com/sass/dart-sass/releases/download/1.25.0/dart-sass-1.25.0-linux-x64.tar.gz \
&& tar xf /tmp/sass.tar.gz -C /bin \
&& chmod -R a+rx /bin/dart-sass/
RUN apt-get update && apt-get install -y \
graphviz \
nodejs \
npm

RUN npm install -g npm

# This is not a nice way to install npm packages, but it is the
# closest it gets similar to venv-way of installing project-specific
# packages.
RUN mkdir -p /nodeapp
WORKDIR /nodeapp
COPY package.json package.json
COPY package-lock.json package-lock.json
RUN npm install
WORKDIR /app

COPY pyproject.toml pyproject.toml
COPY poetry.lock poetry.lock
Expand Down
2 changes: 1 addition & 1 deletion entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ then
fi

# Compile sass
/bin/dart-sass/sass \
/nodeapp/node_modules/.bin/sass \
members/static/members/sass/main.scss members/static/members/css/main.css

python manage.py migrate
Expand Down
4 changes: 3 additions & 1 deletion members/admin/activity_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class ActivityAdmin(admin.ModelAdmin):
list_display = (
"name",
"department",
"activitytype",
"start_date",
"open_invite",
"price_in_dkk",
Expand All @@ -15,7 +16,7 @@ class ActivityAdmin(admin.ModelAdmin):
search_fields = ("name", "department__name")
list_per_page = 20
raw_id_fields = ("department",)
list_filter = ("department", "open_invite")
list_filter = ("department", "open_invite", "activitytype")
save_as = True

# Only view activities on own department
Expand Down Expand Up @@ -44,6 +45,7 @@ def formfield_for_foreignkey(self, db_field, request, **kwargs):
"description": "<p>Aktivitetsnavnet skal afspejle aktivitet samt tidspunkt. F.eks. <em>Forårssæson 2018</em>.</p><p>Tidspunkt er f.eks. <em>Onsdage 17:00-19:00</em></p>",
"fields": (
"name",
"activitytype",
"open_hours",
"description",
"start_date",
Expand Down
2 changes: 1 addition & 1 deletion members/forms/volunteer_signup_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def __init__(self, *args, **kwargs):
widget=forms.DateInput(attrs={"type": "date"}),
)
volunteer_department = forms.ModelChoiceField(
queryset=Department.objects.all(),
queryset=Department.objects.filter(closed_dtm__isnull=True),
required=True,
label="Afdeling",
empty_label="-",
Expand Down
104 changes: 104 additions & 0 deletions members/migrations/0025_activitytype.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Generated by Django 3.1.1 on 2021-04-19 07:14

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):
dependencies = [
("members", "0024_auto_20200902_1108"),
]

def add_activity_types(apps, schema_editor):
ActivityType = apps.get_model("members", "activitytype")
db_alias = schema_editor.connection.alias
ActivityType.objects.using(db_alias).bulk_create(
[
ActivityType(
id="FORLØB",
display_name="Forløb",
description="Aktivitetsforløb med klubaftener.",
),
ActivityType(
id="ARRANGEMENT",
display_name="Arrangement",
description="Endagsarrangementer eller aktivitet der ikke passer ind under forløb.",
),
ActivityType(
id="FORENINGSMEDLEMSKAB",
display_name="Foreningsmedlemskab",
description="Aktiviteten gør deltageren til medlem af din lokalforening, og skal kun bruges til personer der ikke er tilmeldt et forløb.",
),
ActivityType(
id="STØTTEMEDLEMSKAB",
display_name="Støttemedlemskab",
description="Mulighed for at støtte lokalforening eller landsorganisationen økonomisk uden at blive stemmeberettiget medlem.",
),
]
)

def remove_activity_types(apps, schema_editor):
ActivityType = apps.get_model("members", "activitytype")
db_alias = schema_editor.connection.alias
ActivityType.objects.using(db_alias).filter(id="FORLØB").delete()
ActivityType.objects.using(db_alias).filter(id="ARRANGEMENT").delete()
ActivityType.objects.using(db_alias).filter(id="FORENINGSMEDLEMSKAB").delete()
ActivityType.objects.using(db_alias).filter(id="STØTTEMEDLEMSKAB").delete()

operations = [
migrations.CreateModel(
name="ActivityType",
fields=[
(
"id",
models.CharField(
help_text="En sigende identifikator for aktivitetstypen. Fx 'STØTTEMEDLEM'.",
max_length=50,
primary_key=True,
serialize=False,
verbose_name="id",
),
),
(
"display_name",
models.CharField(
help_text="Et visningsnavn for aktivitetstypen. Fx 'Støttemedlem'.",
max_length=100,
verbose_name="Navn",
),
),
(
"description",
models.CharField(
help_text="En beskrivelse af hvad aktivitetstypen dækker over.",
max_length=200,
verbose_name="Beskrivelse",
),
),
(
"updated_dtm",
models.DateTimeField(auto_now=True, verbose_name="Opdateret"),
),
],
options={
"verbose_name": "Aktivitetstype",
"verbose_name_plural": "Aktivitetstyper",
"ordering": ["display_name"],
},
),
migrations.RunPython(add_activity_types, remove_activity_types),
migrations.AddField(
model_name="activity",
name="activitytype",
field=models.ForeignKey(
default="FORLØB",
help_text="Angiv typen af aktivtet. "
+ "Brugere vil se Forløb og Arrangementer under Aktiviteter. "
+ "Medlemskab og Støttemedlemskab vil blive vist på separate sider. "
+ "Normalt vil det kun være sekretariatet der oprettet aktiviteter for medlemskaber.",
on_delete=django.db.models.deletion.CASCADE,
to="members.activitytype",
verbose_name="Aktivitetstype",
),
),
]
3 changes: 3 additions & 0 deletions members/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

# ensure all models are included - otherwise makemigrations fails to detect models
import members.models.activity
import members.models.activitytype
import members.models.activityinvite
import members.models.activityparticipant

Expand All @@ -27,6 +28,7 @@

# Export models not files
from .activity import Activity
from .activitytype import ActivityType
from .activityinvite import ActivityInvite
from .activityparticipant import ActivityParticipant
from .address import Address
Expand Down Expand Up @@ -55,6 +57,7 @@
__all__ = [
Activity,
ActivityInvite,
ActivityType,
ActivityParticipant,
Address,
AdminUserInformation,
Expand Down
10 changes: 10 additions & 0 deletions members/models/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ class Meta:
department = models.ForeignKey("Department", on_delete=models.CASCADE)
union = models.ForeignKey("Union", blank=True, on_delete=models.CASCADE, default=1)
name = models.CharField("Navn", max_length=200)
activitytype = models.ForeignKey(
"ActivityType",
on_delete=models.CASCADE,
default="FORLØB",
verbose_name="Aktivitetstype",
help_text="Angiv typen af aktivtet. "
+ "Brugere vil se Forløb og Arrangementer under Aktiviteter. "
+ "Medlemskab og Støttemedlemskab vil blive vist på separate sider. "
+ "Normalt vil det kun være sekretariatet der oprettet aktiviteter for medlemskaber.",
)
open_hours = models.CharField("Tidspunkt", max_length=200)
responsible_name = models.CharField("Ansvarlig", max_length=200)
responsible_contact = models.EmailField("E-mail")
Expand Down
32 changes: 32 additions & 0 deletions members/models/activitytype.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Added to support different types of activities.
# Makes is possible to filter certain activities out when showing the list to users.

from django.db import models


class ActivityType(models.Model):
class Meta:
verbose_name = "Aktivitetstype"
verbose_name_plural = "Aktivitetstyper"
ordering = ["display_name"]

id = models.CharField(
"id",
primary_key=True,
max_length=50,
help_text="En sigende identifikator for aktivitetstypen. Fx 'STØTTEMEDLEM'.",
)
display_name = models.CharField(
"Navn",
max_length=100,
help_text="Et visningsnavn for aktivitetstypen. Fx 'Støttemedlem'.",
)
description = models.CharField(
"Beskrivelse",
max_length=200,
help_text="En beskrivelse af hvad aktivitetstypen dækker over.",
)
updated_dtm = models.DateTimeField("Opdateret", auto_now=True)

def __str__(self):
return self.display_name
14 changes: 7 additions & 7 deletions members/static/members/sass/base_layout.scss
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
@use "_definitions";
@use "definitions";
@use "buttons";

body {
display: grid;
align-content: space-between;
@include _definitions.for-phone {
@include definitions.for-phone {
grid-template-rows: 1fr 12fr 1fr;
}
// Desktop horizontal nav bar
@include _definitions.for-desktop {
@include definitions.for-desktop {
grid-template-rows: 50px 10fr 1fr;
}
}

body,
html {
height: 100%;
font-family: _definitions.$main_font;
font-family: definitions.$main_font;
width: 100%;
}

Expand All @@ -27,7 +27,7 @@ section {

.info-box {
@extend %rounded-rect;
background-color: _definitions.$light-grey;
background-color: definitions.$light-grey;
padding: 10px;
margin: 10px auto;
width: 66%;
Expand All @@ -49,8 +49,8 @@ main {
@extend %container;
margin-top: 20px;
margin-bottom: 20px;
max-width: _definitions.$max_width;
@include _definitions.for-desktop {
max-width: definitions.$max_width;
@include definitions.for-desktop {
width: 90%;
margin-left: auto;
margin-right: auto;
Expand Down
Loading

0 comments on commit cdf2043

Please sign in to comment.