From b37d5f2f55b4a2e1f57aaccbbe137725ed0634c1 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Sun, 4 Jun 2017 13:24:54 +0300 Subject: [PATCH 01/39] Fix translation issue in payment form --- members/forms.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/members/forms.py b/members/forms.py index 61f5efc..a6e47ce 100644 --- a/members/forms.py +++ b/members/forms.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import ugettext_lazy as _ from members.models import Member, Payment, Request @@ -15,6 +16,9 @@ class PaymentForm(forms.ModelForm): class Meta: model = Payment fields = ['date', 'source', 'member'] + labels = { + 'member': _('Member') + } class ApplicationForm(forms.ModelForm): From eea8c19f50ef2b8dd273422f395d32e2b59a72a5 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Wed, 7 Jun 2017 18:00:08 +0300 Subject: [PATCH 02/39] Create role models --- webapp/models.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/webapp/models.py b/webapp/models.py index ccf5014..3a9ce06 100644 --- a/webapp/models.py +++ b/webapp/models.py @@ -1,5 +1,6 @@ from django.db import models from django.utils import timezone +from django.utils.translation import ugettext_lazy as _ class Tag(models.Model): @@ -35,3 +36,35 @@ class InfoTr(models.Model): topic = models.CharField(max_length=255) content = models.TextField() translation_for = models.ForeignKey('Info', related_name='translations') + + +class BaseRole(models.Model): + ''' + Base model for occupations/roles + ''' + name = models.TextField(_('Name')) + is_board = models.BooleanField(_('Board member')) + + +class PresetRole(BaseRole): + ''' + Model representing a preset occupation in the guild + ''' + description = models.TextField(_('Description')) + summary = models.TextField(_('Summary')) + + +class CustomRole(BaseRole): + ''' + Model representing a user-specified custom occupation + ''' + pass + + +class Role(PresetRole): + ''' + Model representing an active or historical occupation + in an official's history + ''' + start_date = models.DateField(_('Start date')) + end_date = models.DateField(_('End date')) From 3ad38051ea804941eb21674d804233bcc6d3ca28 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Wed, 7 Jun 2017 18:30:37 +0300 Subject: [PATCH 03/39] Add official model and migrations --- locale/en/LC_MESSAGES/django.mo | Bin 6809 -> 6809 bytes locale/en/LC_MESSAGES/django.po | 142 +++++++++++------- locale/fi/LC_MESSAGES/django.mo | Bin 8544 -> 8855 bytes locale/fi/LC_MESSAGES/django.po | 139 ++++++++++------- webapp/admin.py | 3 + ...ole_customrole_official_presetrole_role.py | 69 +++++++++ webapp/migrations/0003_auto_20170607_1825.py | 19 +++ webapp/migrations/0004_auto_20170607_1826.py | 23 +++ webapp/models.py | 15 ++ 9 files changed, 305 insertions(+), 105 deletions(-) create mode 100644 webapp/migrations/0002_baserole_customrole_official_presetrole_role.py create mode 100644 webapp/migrations/0003_auto_20170607_1825.py create mode 100644 webapp/migrations/0004_auto_20170607_1826.py diff --git a/locale/en/LC_MESSAGES/django.mo b/locale/en/LC_MESSAGES/django.mo index bd4b884824b8c5d5555c83fcb19b93e2f7dd47c5..213409bceb643dc4a5f3a4780a70b8d633b2abdb 100644 GIT binary patch delta 20 ccmbPfI@5H+Z9#T(1w#ufBcsia1h;bl08Bgw0{{R3 delta 20 ccmbPfI@5H+Z9#TJ1w%_KBZJM41h;bl088-(`~Uy| diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po index d283642..b9a67b3 100644 --- a/locale/en/LC_MESSAGES/django.po +++ b/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-06-01 19:20+0300\n" +"POT-Creation-Date: 2017-06-07 18:22+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -70,72 +70,78 @@ msgstr "Manage Rotations" msgid "Create/Delete" msgstr "Create/Delete" -#: infoscreen/templates/infoscreen_admin.html:48 +#: infoscreen/templates/infoscreen_admin.html:43 +#: infoscreen/templates/infoscreen_admin.html:152 +#: members/templates/members_base.html:75 members/templates/settings.html:11 +msgid "Settings" +msgstr "Settings" + +#: infoscreen/templates/infoscreen_admin.html:49 msgid "Create new item" msgstr "Create new item" -#: infoscreen/templates/infoscreen_admin.html:49 +#: infoscreen/templates/infoscreen_admin.html:50 #, fuzzy #| msgid "Create new item" msgid "Create a new item by type" msgstr "Create new item" -#: infoscreen/templates/infoscreen_admin.html:52 +#: infoscreen/templates/infoscreen_admin.html:53 msgid "Item type" msgstr "Item type" -#: infoscreen/templates/infoscreen_admin.html:63 -#: infoscreen/templates/infoscreen_admin.html:83 +#: infoscreen/templates/infoscreen_admin.html:64 +#: infoscreen/templates/infoscreen_admin.html:84 msgid "Info items" msgstr "Info items" -#: infoscreen/templates/infoscreen_admin.html:64 -#: infoscreen/templates/infoscreen_admin.html:84 +#: infoscreen/templates/infoscreen_admin.html:65 +#: infoscreen/templates/infoscreen_admin.html:85 msgid "Infoitems available for rotations" msgstr "Infoitems available for rotations" -#: infoscreen/templates/infoscreen_admin.html:67 -#: infoscreen/templates/infoscreen_admin.html:87 +#: infoscreen/templates/infoscreen_admin.html:68 +#: infoscreen/templates/infoscreen_admin.html:88 msgid "Item" msgstr "Item" -#: infoscreen/templates/infoscreen_admin.html:68 -#: infoscreen/templates/infoscreen_admin.html:88 +#: infoscreen/templates/infoscreen_admin.html:69 +#: infoscreen/templates/infoscreen_admin.html:89 msgid "Type" msgstr "Type" -#: infoscreen/templates/infoscreen_admin.html:69 -#: infoscreen/templates/infoscreen_admin.html:74 -#: infoscreen/templates/infoscreen_admin.html:91 -#: infoscreen/templates/infoscreen_admin.html:98 +#: infoscreen/templates/infoscreen_admin.html:70 +#: infoscreen/templates/infoscreen_admin.html:75 +#: infoscreen/templates/infoscreen_admin.html:92 +#: infoscreen/templates/infoscreen_admin.html:99 #: infoscreen/templates/infoscreen_admin.html:112 #: infoscreen/templates/infoscreen_admin.html:116 -#: infoscreen/templates/infoscreen_admin.html:134 -#: infoscreen/templates/infoscreen_admin.html:140 +#: infoscreen/templates/infoscreen_admin.html:132 +#: infoscreen/templates/infoscreen_admin.html:138 #: members/templates/member_edit.html:20 members/templates/payment_edit.html:20 msgid "Delete" msgstr "Delete" -#: infoscreen/templates/infoscreen_admin.html:89 +#: infoscreen/templates/infoscreen_admin.html:90 msgid "Set duration" msgstr "Set duration" -#: infoscreen/templates/infoscreen_admin.html:90 +#: infoscreen/templates/infoscreen_admin.html:91 msgid "Add to rotation" msgstr "Add to rotation" -#: infoscreen/templates/infoscreen_admin.html:97 +#: infoscreen/templates/infoscreen_admin.html:98 msgid "Add" msgstr "Add" #: infoscreen/templates/infoscreen_admin.html:106 -#: infoscreen/templates/infoscreen_admin.html:131 +#: infoscreen/templates/infoscreen_admin.html:129 msgid "Rotation" msgstr "Rotation" #: infoscreen/templates/infoscreen_admin.html:106 -#: infoscreen/templates/infoscreen_admin.html:133 -#: infoscreen/templates/infoscreen_admin.html:139 +#: infoscreen/templates/infoscreen_admin.html:131 +#: infoscreen/templates/infoscreen_admin.html:137 msgid "Preview" msgstr "Preview" @@ -151,26 +157,54 @@ msgstr "Instance" msgid "Duration" msgstr "Duration" -#: infoscreen/templates/infoscreen_admin.html:125 +#: infoscreen/templates/infoscreen_admin.html:123 msgid "Rotations" msgstr "Rotations" -#: infoscreen/templates/infoscreen_admin.html:127 +#: infoscreen/templates/infoscreen_admin.html:125 msgid "Select rotation to edit" msgstr "Select rotation to edit" -#: infoscreen/templates/infoscreen_admin.html:132 +#: infoscreen/templates/infoscreen_admin.html:130 msgid "id" msgstr "id" -#: infoscreen/templates/infoscreen_admin.html:143 +#: infoscreen/templates/infoscreen_admin.html:141 webapp/models.py:46 msgid "Name" msgstr "Name" -#: infoscreen/templates/infoscreen_admin.html:144 +#: infoscreen/templates/infoscreen_admin.html:142 msgid "Create new" msgstr "Create new" +#: infoscreen/templates/infoscreen_admin.html:157 +#: members/templates/settings.html:17 +msgid "Language" +msgstr "Language" + +#: infoscreen/templates/infoscreen_admin.html:161 +#: members/templates/settings.html:20 sikweb/settings-sample.py:179 +#: sikweb/settings.py:178 +msgid "Finnish" +msgstr "Finnish" + +#: infoscreen/templates/infoscreen_admin.html:162 +#: members/templates/settings.html:21 sikweb/settings-sample.py:178 +#: sikweb/settings.py:177 +msgid "English" +msgstr "English" + +#: infoscreen/templates/infoscreen_admin.html:166 +#: members/templates/settings.html:23 +#, fuzzy +#| msgid "Submitted" +msgid "Submit" +msgstr "Submitted" + +#: members/forms.py:20 members/tables.py:24 +msgid "Member" +msgstr "Member" + #: members/models.py:16 msgid "First name" msgstr "First name" @@ -231,10 +265,6 @@ msgstr "Edit" msgid "Options" msgstr "Options" -#: members/tables.py:24 -msgid "Member" -msgstr "Member" - #: members/templates/application_edit.html:9 msgid "Edit application" msgstr "Edit application" @@ -399,10 +429,6 @@ msgstr "List applications" msgid "Application form" msgstr "Application form" -#: members/templates/members_base.html:75 members/templates/settings.html:11 -msgid "Settings" -msgstr "Settings" - #: members/templates/payment_delete_confirm.html:9 msgid "Are you sure you want to delete this payment?" msgstr "Are you sure you want to delete this payment?" @@ -415,20 +441,6 @@ msgstr "Edit payment" msgid "Payment events" msgstr "Payment events" -#: members/templates/settings.html:17 -msgid "Language" -msgstr "Language" - -#: members/templates/settings.html:20 sikweb/settings-sample.py:179 -#: sikweb/settings.py:177 -msgid "Finnish" -msgstr "Finnish" - -#: members/templates/settings.html:21 sikweb/settings-sample.py:178 -#: sikweb/settings.py:176 -msgid "English" -msgstr "English" - #: members/views.py:129 members/views.py:186 members/views.py:205 msgid "No member id specified" msgstr "No member id specified" @@ -519,6 +531,34 @@ msgstr "Successfully deleted member" msgid "Copyright Aalto-yliopiston Sähköinsinöörikilta ry" msgstr "Copyright Aalto-yliopiston Sähköinsinöörikilta ry" +#: webapp/models.py:47 +#, fuzzy +#| msgid "Add member" +msgid "Board member" +msgstr "Add member" + +#: webapp/models.py:54 +#, fuzzy +#| msgid "Duration" +msgid "Description" +msgstr "Duration" + +#: webapp/models.py:55 +msgid "Summary" +msgstr "" + +#: webapp/models.py:70 +msgid "Start date" +msgstr "" + +#: webapp/models.py:71 +msgid "End date" +msgstr "" + +#: webapp/models.py:79 +msgid "Phone number" +msgstr "" + #: webapp/templates/admin_index.html:6 msgid "SIK Admin" msgstr "SIK Admin" diff --git a/locale/fi/LC_MESSAGES/django.mo b/locale/fi/LC_MESSAGES/django.mo index 5fd3dd7488ee28b7cf0955f7e431cac5db494fae..d36e122e7e41e82f61b9f14554fa3888831bd591 100644 GIT binary patch delta 3122 zcmZA3drZ}39LMqJ0D_=+0k05vyd#)~W`as8fsz7RUP?>jAV)aD0X&>Tkm*qjYHAll z%FStWF`PA8+ev5l)+x)mE@rb_o3^>((pl5yA8K2@Kj%EQ)wA>cy`JZHdG5a-{95>W zaqvP)T$drW6Za5BamIwOu0ID--T-6Vn2%rK8>maw1EV%#Eag_r!L1mNM==fG#Y{YH zy@I+wG1-_TV}d4`4Cl-!q;4}22V<@+FT^2~%TV{N$EjG0_u_t}&*miZGp9M|zVr5c zAF3l)F#+QT88Zt9;dt6NMUjj#HK?BM!7=!@EuXgKD>$0-N%W4Mn+d3nPUk?~WC*w)f0Di}*n96+X`T|sg6{z|=sDU)=JnfryGTOZ_ z=>#4^Ey)qaUPM)V9o3K)n$)Q8#|H?6l(&;5<+Kn4ZPKsIX4m!RH)a#VX8Gnju} z@N+^VY_T`Cp&IT$^?VO%q+O_nkDw|zj%w%&d;N?(e+k)#<~nL-6Zo!cMn|IdL?-I| z^i1ZzfXsYOsG+T>8Rj z8I(&<1KWc9Oz`A-KYlkqZ&Mn>cCNa0Y64{Y!MG@ zCdyD9S%=zmJ1_?Kp+oP#)^#1xKujkdBiuwSp$_?pIfO=ELMS~;@Vp5St%Qeon3zW> z(TC{g7B>=)5K3xTvpSKOLa2RH4($XpW*Uiyh^L7*LTj#+PjKsh(p*ZK0VS;|n?92C zv3b(wb5UPQAF-XNBc38w5iLYyH|F4Tgx=L{oqH2ggW58h#LdJOLVu#R603>HL?NNY zc$6q0l(Z=IL=7>OP)a2DOh(e<9P@}GLJO>OEjw2%y+*?&_hIbNm6OIxX#o=>5eSWY}cD6Js$ z_TNp_Wct~{gE*VeR@FXVODL_35;;D>(Phg!tZ_Jr&=%JARNA1?&5UIE9|qHiMZ{uz zPHZBYLcK}dF-e6DE?-JWL%9EdWB)OY5_&kk%PeXm@*+J#;Rn97x-yO;v{71}y znudC}vp(Rhbo)97q_ht4yL|r0WwRns>Gk+SZ7C}q@d2;b9AvA3CaYy{pK(i~*)Ojjx&9Ksj#>PNnxZBel?)HYe z!`;4ccW7+-#*46(1R#WO}(o>=DGxs_MuJm}CJxzXh L9W}jK;dJ~1|C2=2 delta 2843 zcmZA2drZ}39LMqJfIcV~Q=*KS zhnbj+<<{+}>z_fIbj(pQd`vH2+-pu?G`?rcXVFc082OmXeC6OcE<*P$#xQ2H9Ql}X zTdqY7pdK}sb}Ym$ybT8eI>vlMMkD+aJ(w^jSS~`9H)0a*MMi9TPy>7&xyAIOIv7L^ z@b~nz>rlg;6*glTZzNY&iqD)GR_ZywsM0v9`9uKp)P>#@v1&8!ObnC(XW z{-*tX5Y@rAr~!|nR`Ms*qdkQhXeZ000d-*!I)}+auMs+k8hz? zsETRo`UcdVH=_pBifZ^(ydB?04S2{pff`sWCsggs3+k9GGHS3GnY3Aj?1I^h4BE7z zX5!%8*o#YW7}cSR<bduzwx9&{+^mpkfR)@(AwE z!CchyzXjFNK~#fBQ8PGZ>rbK%Wxp+dg4&8NPy-r4J#Lp!D{uuh!7-`l{~8%J7{-RG zgLqVjsi+&XQ7e;=nrQ`U#cEJ1v=tX(JL>u#R7ZVSi6>C)|BN~VQ`W!G(Tz9AsN;p4 zG|l)9)ZVT^w#}?Zb=Yj{J5e(`V9SS59e1M!{sL--eW;F4q3-_})z6Uq{o(@FUq6gf zp%>01YAM4Rm6k9OwfD)W`dnOwrKpY$p;n|D^*FtZnxP;0m_fdno4Jgs_y-2g2=9B{ z?@4C;)o>;ivKaL$u0%Dw!Ctrxbz=)^$@kd$Zd3<7w){To{?n-I&!HwVVt>DgI)qnH zEB%i{rhrT`CC#7~z1V@7_zLP!eu{ZGhMGy7muOx>^W*{l(d(+HlNr>%%nOpJdNf_qMEpic$iSyM5x2H zDv-1-N?Nr?=|Auvt_mg=NE*Ek(~e*<@b=On)a;eg2tCi6i5B8PLQ8!gp&2bDbolNe zSX|Rilo3ig8@$)dQ-oHnM9+T#8Kvb!M<5scDux(2UKwVKt<1&;Y~F2s2%oTd z@ffj{=pt4Ttwb*2u!Y_=aNl``5+Qx%{W*u62dyd-E5U6y*7@$NwJczn*l) bo^s<~a5(i7 diff --git a/locale/fi/LC_MESSAGES/django.po b/locale/fi/LC_MESSAGES/django.po index b7de81d..5c39c26 100644 --- a/locale/fi/LC_MESSAGES/django.po +++ b/locale/fi/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-06-01 19:20+0300\n" +"POT-Creation-Date: 2017-06-07 18:22+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -71,70 +71,76 @@ msgstr "Hallinnoi Rotaatioita" msgid "Create/Delete" msgstr "Lisää/Poista" -#: infoscreen/templates/infoscreen_admin.html:48 +#: infoscreen/templates/infoscreen_admin.html:43 +#: infoscreen/templates/infoscreen_admin.html:152 +#: members/templates/members_base.html:75 members/templates/settings.html:11 +msgid "Settings" +msgstr "Asetukset" + +#: infoscreen/templates/infoscreen_admin.html:49 msgid "Create new item" msgstr "Luo uusi dia" -#: infoscreen/templates/infoscreen_admin.html:49 +#: infoscreen/templates/infoscreen_admin.html:50 msgid "Create a new item by type" msgstr "Luo uusi dia tyypin perusteella" -#: infoscreen/templates/infoscreen_admin.html:52 +#: infoscreen/templates/infoscreen_admin.html:53 msgid "Item type" msgstr "Diatyyppi" -#: infoscreen/templates/infoscreen_admin.html:63 -#: infoscreen/templates/infoscreen_admin.html:83 +#: infoscreen/templates/infoscreen_admin.html:64 +#: infoscreen/templates/infoscreen_admin.html:84 msgid "Info items" msgstr "Diat" -#: infoscreen/templates/infoscreen_admin.html:64 -#: infoscreen/templates/infoscreen_admin.html:84 +#: infoscreen/templates/infoscreen_admin.html:65 +#: infoscreen/templates/infoscreen_admin.html:85 msgid "Infoitems available for rotations" msgstr "Rotaatioon lisättävät diat" -#: infoscreen/templates/infoscreen_admin.html:67 -#: infoscreen/templates/infoscreen_admin.html:87 +#: infoscreen/templates/infoscreen_admin.html:68 +#: infoscreen/templates/infoscreen_admin.html:88 msgid "Item" msgstr "Dia" -#: infoscreen/templates/infoscreen_admin.html:68 -#: infoscreen/templates/infoscreen_admin.html:88 +#: infoscreen/templates/infoscreen_admin.html:69 +#: infoscreen/templates/infoscreen_admin.html:89 msgid "Type" msgstr "Tyyppi" -#: infoscreen/templates/infoscreen_admin.html:69 -#: infoscreen/templates/infoscreen_admin.html:74 -#: infoscreen/templates/infoscreen_admin.html:91 -#: infoscreen/templates/infoscreen_admin.html:98 +#: infoscreen/templates/infoscreen_admin.html:70 +#: infoscreen/templates/infoscreen_admin.html:75 +#: infoscreen/templates/infoscreen_admin.html:92 +#: infoscreen/templates/infoscreen_admin.html:99 #: infoscreen/templates/infoscreen_admin.html:112 #: infoscreen/templates/infoscreen_admin.html:116 -#: infoscreen/templates/infoscreen_admin.html:134 -#: infoscreen/templates/infoscreen_admin.html:140 +#: infoscreen/templates/infoscreen_admin.html:132 +#: infoscreen/templates/infoscreen_admin.html:138 #: members/templates/member_edit.html:20 members/templates/payment_edit.html:20 msgid "Delete" msgstr "Poista" -#: infoscreen/templates/infoscreen_admin.html:89 +#: infoscreen/templates/infoscreen_admin.html:90 msgid "Set duration" msgstr "Aseta kesto" -#: infoscreen/templates/infoscreen_admin.html:90 +#: infoscreen/templates/infoscreen_admin.html:91 msgid "Add to rotation" msgstr "Lisää rotaatioon" -#: infoscreen/templates/infoscreen_admin.html:97 +#: infoscreen/templates/infoscreen_admin.html:98 msgid "Add" msgstr "Lisää" #: infoscreen/templates/infoscreen_admin.html:106 -#: infoscreen/templates/infoscreen_admin.html:131 +#: infoscreen/templates/infoscreen_admin.html:129 msgid "Rotation" msgstr "Rotaatio" #: infoscreen/templates/infoscreen_admin.html:106 -#: infoscreen/templates/infoscreen_admin.html:133 -#: infoscreen/templates/infoscreen_admin.html:139 +#: infoscreen/templates/infoscreen_admin.html:131 +#: infoscreen/templates/infoscreen_admin.html:137 msgid "Preview" msgstr "Esikatsele" @@ -150,26 +156,52 @@ msgstr "Dia" msgid "Duration" msgstr "Kesto" -#: infoscreen/templates/infoscreen_admin.html:125 +#: infoscreen/templates/infoscreen_admin.html:123 msgid "Rotations" msgstr "Rotaatiot" -#: infoscreen/templates/infoscreen_admin.html:127 +#: infoscreen/templates/infoscreen_admin.html:125 msgid "Select rotation to edit" msgstr "Valitse muokattava rotaatio" -#: infoscreen/templates/infoscreen_admin.html:132 +#: infoscreen/templates/infoscreen_admin.html:130 msgid "id" msgstr "id" -#: infoscreen/templates/infoscreen_admin.html:143 +#: infoscreen/templates/infoscreen_admin.html:141 webapp/models.py:46 msgid "Name" msgstr "Nimi" -#: infoscreen/templates/infoscreen_admin.html:144 +#: infoscreen/templates/infoscreen_admin.html:142 msgid "Create new" msgstr "Luo uusi" +#: infoscreen/templates/infoscreen_admin.html:157 +#: members/templates/settings.html:17 +msgid "Language" +msgstr "Kieli" + +#: infoscreen/templates/infoscreen_admin.html:161 +#: members/templates/settings.html:20 sikweb/settings-sample.py:179 +#: sikweb/settings.py:178 +msgid "Finnish" +msgstr "suomi" + +#: infoscreen/templates/infoscreen_admin.html:162 +#: members/templates/settings.html:21 sikweb/settings-sample.py:178 +#: sikweb/settings.py:177 +msgid "English" +msgstr "englanti" + +#: infoscreen/templates/infoscreen_admin.html:166 +#: members/templates/settings.html:23 +msgid "Submit" +msgstr "Lisää" + +#: members/forms.py:20 members/tables.py:24 +msgid "Member" +msgstr "Jäsen" + #: members/models.py:16 msgid "First name" msgstr "Etunimi" @@ -230,10 +262,6 @@ msgstr "Muokkaa" msgid "Options" msgstr "Asetukset" -#: members/tables.py:24 -msgid "Member" -msgstr "Jäsen" - #: members/templates/application_edit.html:9 msgid "Edit application" msgstr "Muokkaa hakemusta" @@ -403,10 +431,6 @@ msgstr "Hakemuslistaus" msgid "Application form" msgstr "Jäsenhakemuslomake" -#: members/templates/members_base.html:75 members/templates/settings.html:11 -msgid "Settings" -msgstr "Asetukset" - #: members/templates/payment_delete_confirm.html:9 msgid "Are you sure you want to delete this payment?" msgstr "Oletko varma, että haluat poistaa tämän maksutapahtuman?" @@ -419,20 +443,6 @@ msgstr "Muokkaa maksua" msgid "Payment events" msgstr "Maksutapahtumat" -#: members/templates/settings.html:17 -msgid "Language" -msgstr "Kieli" - -#: members/templates/settings.html:20 sikweb/settings-sample.py:179 -#: sikweb/settings.py:177 -msgid "Finnish" -msgstr "suomi" - -#: members/templates/settings.html:21 sikweb/settings-sample.py:178 -#: sikweb/settings.py:176 -msgid "English" -msgstr "englanti" - #: members/views.py:129 members/views.py:186 members/views.py:205 msgid "No member id specified" msgstr "Jäsenen ID ei määritelty" @@ -521,6 +531,30 @@ msgstr "Kaikki jäsenkonfliktit ratkaistu onnistuneesti." msgid "Copyright Aalto-yliopiston Sähköinsinöörikilta ry" msgstr "Copyright Aalto-yliopiston Sähköinsinöörikilta ry" +#: webapp/models.py:47 +msgid "Board member" +msgstr "Hallituksen jäsen" + +#: webapp/models.py:54 +msgid "Description" +msgstr "Kuvaus" + +#: webapp/models.py:55 +msgid "Summary" +msgstr "Tiivistelmä" + +#: webapp/models.py:70 +msgid "Start date" +msgstr "Alkupäivämäärä" + +#: webapp/models.py:71 +msgid "End date" +msgstr "Loppupäivämäärä" + +#: webapp/models.py:79 +msgid "Phone number" +msgstr "Puhelinnumero" + #: webapp/templates/admin_index.html:6 msgid "SIK Admin" msgstr "SIK Hallintapaneeli" @@ -564,6 +598,3 @@ msgstr "Sössö" #: webapp/templates/navigation.html:32 msgid "Contact" msgstr "Yhteystiedot" - -#~ msgid "Select" -#~ msgstr "Valitse" diff --git a/webapp/admin.py b/webapp/admin.py index 8c38f3f..6e469fd 100644 --- a/webapp/admin.py +++ b/webapp/admin.py @@ -1,3 +1,6 @@ from django.contrib import admin +from webapp.models import Official, Role # Register your models here. +admin.site.register(Official) +admin.site.register(Role) diff --git a/webapp/migrations/0002_baserole_customrole_official_presetrole_role.py b/webapp/migrations/0002_baserole_customrole_official_presetrole_role.py new file mode 100644 index 0000000..241045d --- /dev/null +++ b/webapp/migrations/0002_baserole_customrole_official_presetrole_role.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-06-07 15:20 +from __future__ import unicode_literals + +from django.conf import settings +import django.contrib.auth.models +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0008_alter_user_username_max_length'), + ('webapp', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='BaseRole', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.TextField(verbose_name='Name')), + ('is_board', models.BooleanField(verbose_name='Board member')), + ], + ), + migrations.CreateModel( + name='Official', + fields=[ + ('user_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)), + ('phone_number', models.TextField(verbose_name='Phone number')), + ], + options={ + 'verbose_name': 'user', + 'verbose_name_plural': 'users', + 'abstract': False, + }, + bases=('auth.user',), + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + migrations.CreateModel( + name='CustomRole', + fields=[ + ('baserole_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='webapp.BaseRole')), + ], + bases=('webapp.baserole',), + ), + migrations.CreateModel( + name='PresetRole', + fields=[ + ('baserole_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='webapp.BaseRole')), + ('description', models.TextField(verbose_name='Description')), + ('summary', models.TextField(verbose_name='Summary')), + ], + bases=('webapp.baserole',), + ), + migrations.CreateModel( + name='Role', + fields=[ + ('presetrole_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='webapp.PresetRole')), + ('start_date', models.DateField(verbose_name='Start date')), + ('end_date', models.DateField(verbose_name='End date')), + ('official', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='roles', to='webapp.Official')), + ], + bases=('webapp.presetrole',), + ), + ] diff --git a/webapp/migrations/0003_auto_20170607_1825.py b/webapp/migrations/0003_auto_20170607_1825.py new file mode 100644 index 0000000..0cc68bc --- /dev/null +++ b/webapp/migrations/0003_auto_20170607_1825.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-06-07 15:25 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapp', '0002_baserole_customrole_official_presetrole_role'), + ] + + operations = [ + migrations.AlterModelOptions( + name='role', + options={'verbose_name': 'Official'}, + ), + ] diff --git a/webapp/migrations/0004_auto_20170607_1826.py b/webapp/migrations/0004_auto_20170607_1826.py new file mode 100644 index 0000000..0380a34 --- /dev/null +++ b/webapp/migrations/0004_auto_20170607_1826.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-06-07 15:26 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapp', '0003_auto_20170607_1825'), + ] + + operations = [ + migrations.AlterModelOptions( + name='official', + options={'verbose_name': 'Official'}, + ), + migrations.AlterModelOptions( + name='role', + options={'verbose_name': 'Role'}, + ), + ] diff --git a/webapp/models.py b/webapp/models.py index 3a9ce06..91f89f9 100644 --- a/webapp/models.py +++ b/webapp/models.py @@ -1,6 +1,7 @@ from django.db import models from django.utils import timezone from django.utils.translation import ugettext_lazy as _ +from django.contrib.auth.models import User class Tag(models.Model): @@ -66,5 +67,19 @@ class Role(PresetRole): Model representing an active or historical occupation in an official's history ''' + class Meta: + verbose_name = _('Role') + start_date = models.DateField(_('Start date')) end_date = models.DateField(_('End date')) + official = models.ForeignKey('Official', related_name='roles') + + +class Official(User): + ''' + Model representing a guild official + ''' + class Meta: + verbose_name = _('Official') + + phone_number = models.TextField(_('Phone number')) From bd0522f79a78cd9d48519a22334404aa5afb5213 Mon Sep 17 00:00:00 2001 From: Ilkka Oksanen Date: Wed, 7 Jun 2017 18:38:04 +0300 Subject: [PATCH 04/39] Rework webapp models and add translation framework --- requirements.txt | 1 + sikweb/settings-sample.py | 3 +- webapp/__init__.py | 1 + webapp/admin.py | 7 +- webapp/apps.py | 3 + webapp/migrations/0002_auto_20170601_1919.py | 71 +++++++++++++++++++ webapp/migrations/0003_auto_20170607_1643.py | 45 ++++++++++++ webapp/migrations/0004_auto_20170607_1712.py | 20 ++++++ webapp/migrations/0005_auto_20170607_1717.py | 25 +++++++ .../0006_delete_deprecated_models.py | 23 ++++++ webapp/migrations/0007_auto_20170607_1815.py | 61 ++++++++++++++++ webapp/migrations/0008_auto_20170607_1828.py | 55 ++++++++++++++ webapp/models.py | 47 ++++++------ webapp/translation.py | 19 +++++ webapp/utils.py | 6 ++ 15 files changed, 359 insertions(+), 28 deletions(-) create mode 100644 webapp/migrations/0002_auto_20170601_1919.py create mode 100644 webapp/migrations/0003_auto_20170607_1643.py create mode 100644 webapp/migrations/0004_auto_20170607_1712.py create mode 100644 webapp/migrations/0005_auto_20170607_1717.py create mode 100644 webapp/migrations/0006_delete_deprecated_models.py create mode 100644 webapp/migrations/0007_auto_20170607_1815.py create mode 100644 webapp/migrations/0008_auto_20170607_1828.py create mode 100644 webapp/translation.py create mode 100644 webapp/utils.py diff --git a/requirements.txt b/requirements.txt index 2fa49fb..f9329ef 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,3 +23,4 @@ django-bootstrap3==8.2.3 django-tables2==1.6.1 pep8==1.7.0 dealer==2.0.5 +django-modeltranslation==0.12.1 diff --git a/sikweb/settings-sample.py b/sikweb/settings-sample.py index 755f6c4..40ec433 100644 --- a/sikweb/settings-sample.py +++ b/sikweb/settings-sample.py @@ -35,6 +35,7 @@ ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ + 'modeltranslation', # has to be before admin for translation admin stuff to work 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', @@ -175,8 +176,8 @@ LOGPATH = "logs/debug.log" # https://docs.djangoproject.com/en/1.9/topics/i18n/ LANGUAGES = ( - ('en', _('English')), ('fi', _('Finnish')), + ('en', _('English')), ) LANGUAGE_CODE = 'fi' diff --git a/webapp/__init__.py b/webapp/__init__.py index e69de29..8b13789 100644 --- a/webapp/__init__.py +++ b/webapp/__init__.py @@ -0,0 +1 @@ + diff --git a/webapp/admin.py b/webapp/admin.py index 8c38f3f..a128874 100644 --- a/webapp/admin.py +++ b/webapp/admin.py @@ -1,3 +1,8 @@ from django.contrib import admin +from webapp.models import Feed, Tag, BaseFeed, Event +from modeltranslation.admin import TranslationAdmin -# Register your models here. + +admin.site.register(Feed, TranslationAdmin) +admin.site.register(Tag, TranslationAdmin) +admin.site.register(Event, TranslationAdmin) diff --git a/webapp/apps.py b/webapp/apps.py index fcacfff..55fa92c 100644 --- a/webapp/apps.py +++ b/webapp/apps.py @@ -3,3 +3,6 @@ from django.apps import AppConfig class WebappConfig(AppConfig): name = 'webapp' + + def ready(self): + import webapp.translations diff --git a/webapp/migrations/0002_auto_20170601_1919.py b/webapp/migrations/0002_auto_20170601_1919.py new file mode 100644 index 0000000..b34cbf9 --- /dev/null +++ b/webapp/migrations/0002_auto_20170601_1919.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-06-01 16:19 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.utils.timezone +import webapp.utils + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapp', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Feed', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('publish_time', models.DateTimeField(default=django.utils.timezone.now)), + ('autohide', models.BooleanField(default=False)), + ('autohide_time', models.DateTimeField(default=webapp.utils.month_from_now)), + ('topic', models.CharField(max_length=255)), + ('description', models.CharField(max_length=255)), + ('content', models.TextField()), + ], + ), + migrations.RemoveField( + model_name='info', + name='tags', + ), + migrations.RemoveField( + model_name='infotr', + name='translation_for', + ), + migrations.RemoveField( + model_name='tagtr', + name='translation_for', + ), + migrations.RemoveField( + model_name='tag', + name='dummyname', + ), + migrations.AddField( + model_name='tag', + name='name', + field=models.CharField(default='', max_length=127), + preserve_default=False, + ), + migrations.AddField( + model_name='tag', + name='slug', + field=models.SlugField(default=''), + preserve_default=False, + ), + migrations.DeleteModel( + name='Info', + ), + migrations.DeleteModel( + name='InfoTr', + ), + migrations.DeleteModel( + name='TagTr', + ), + migrations.AddField( + model_name='feed', + name='tags', + field=models.ManyToManyField(related_name='news', to='webapp.Tag'), + ), + ] diff --git a/webapp/migrations/0003_auto_20170607_1643.py b/webapp/migrations/0003_auto_20170607_1643.py new file mode 100644 index 0000000..004423e --- /dev/null +++ b/webapp/migrations/0003_auto_20170607_1643.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-06-07 13:43 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapp', '0002_auto_20170601_1919'), + ] + + operations = [ + migrations.AddField( + model_name='feed', + name='content_en', + field=models.TextField(null=True), + ), + migrations.AddField( + model_name='feed', + name='content_fi', + field=models.TextField(null=True), + ), + migrations.AddField( + model_name='feed', + name='description_en', + field=models.CharField(max_length=255, null=True), + ), + migrations.AddField( + model_name='feed', + name='description_fi', + field=models.CharField(max_length=255, null=True), + ), + migrations.AddField( + model_name='feed', + name='topic_en', + field=models.CharField(max_length=255, null=True), + ), + migrations.AddField( + model_name='feed', + name='topic_fi', + field=models.CharField(max_length=255, null=True), + ), + ] diff --git a/webapp/migrations/0004_auto_20170607_1712.py b/webapp/migrations/0004_auto_20170607_1712.py new file mode 100644 index 0000000..12688ce --- /dev/null +++ b/webapp/migrations/0004_auto_20170607_1712.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-06-07 14:12 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapp', '0003_auto_20170607_1643'), + ] + + operations = [ + migrations.AlterField( + model_name='feed', + name='tags', + field=models.ManyToManyField(blank=True, related_name='news', to='webapp.Tag'), + ), + ] diff --git a/webapp/migrations/0005_auto_20170607_1717.py b/webapp/migrations/0005_auto_20170607_1717.py new file mode 100644 index 0000000..1d77c2a --- /dev/null +++ b/webapp/migrations/0005_auto_20170607_1717.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-06-07 14:17 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapp', '0004_auto_20170607_1712'), + ] + + operations = [ + migrations.AddField( + model_name='tag', + name='name_en', + field=models.CharField(max_length=127, null=True), + ), + migrations.AddField( + model_name='tag', + name='name_fi', + field=models.CharField(max_length=127, null=True), + ), + ] diff --git a/webapp/migrations/0006_delete_deprecated_models.py b/webapp/migrations/0006_delete_deprecated_models.py new file mode 100644 index 0000000..81d1d82 --- /dev/null +++ b/webapp/migrations/0006_delete_deprecated_models.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-06-01 16:19 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.utils.timezone +import webapp.utils + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapp', '0005_auto_20170607_1717'), + ] + + operations = [ + migrations.DeleteModel( + name='Tag', + ), + migrations.DeleteModel( + name='Feed', + ), + ] diff --git a/webapp/migrations/0007_auto_20170607_1815.py b/webapp/migrations/0007_auto_20170607_1815.py new file mode 100644 index 0000000..71660fd --- /dev/null +++ b/webapp/migrations/0007_auto_20170607_1815.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-06-07 15:15 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import webapp.utils + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('webapp', '0006_delete_deprecated_models'), + ] + + operations = [ + migrations.CreateModel( + name='BaseFeed', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('visible', models.BooleanField(default=True)), + ('title', models.CharField(max_length=255)), + ('description', models.CharField(max_length=255)), + ('content', models.TextField()), + ], + ), + migrations.CreateModel( + name='Tag', + fields=[ + ('slug', models.SlugField(primary_key=True, serialize=False)), + ('name', models.CharField(max_length=127)), + ('icon', models.ImageField(upload_to='')), + ], + ), + migrations.CreateModel( + name='Event', + fields=[ + ('basefeed_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='webapp.BaseFeed')), + ('start_time', models.DateTimeField(default=django.utils.timezone.now)), + ('end_time', models.DateTimeField(default=django.utils.timezone.now)), + ], + bases=('webapp.basefeed',), + ), + migrations.CreateModel( + name='Feed', + fields=[ + ('basefeed_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='webapp.BaseFeed')), + ('publish_time', models.DateTimeField(default=django.utils.timezone.now)), + ('autohide', models.DateTimeField(default=webapp.utils.month_from_now)), + ], + bases=('webapp.basefeed',), + ), + migrations.AddField( + model_name='basefeed', + name='tags', + field=models.ManyToManyField(blank=True, related_name='feeds', to='webapp.Tag'), + ), + ] diff --git a/webapp/migrations/0008_auto_20170607_1828.py b/webapp/migrations/0008_auto_20170607_1828.py new file mode 100644 index 0000000..6940792 --- /dev/null +++ b/webapp/migrations/0008_auto_20170607_1828.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-06-07 15:28 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapp', '0007_auto_20170607_1815'), + ] + + operations = [ + migrations.AddField( + model_name='basefeed', + name='content_en', + field=models.TextField(null=True), + ), + migrations.AddField( + model_name='basefeed', + name='content_fi', + field=models.TextField(null=True), + ), + migrations.AddField( + model_name='basefeed', + name='description_en', + field=models.CharField(max_length=255, null=True), + ), + migrations.AddField( + model_name='basefeed', + name='description_fi', + field=models.CharField(max_length=255, null=True), + ), + migrations.AddField( + model_name='basefeed', + name='title_en', + field=models.CharField(max_length=255, null=True), + ), + migrations.AddField( + model_name='basefeed', + name='title_fi', + field=models.CharField(max_length=255, null=True), + ), + migrations.AddField( + model_name='tag', + name='name_en', + field=models.CharField(max_length=127, null=True), + ), + migrations.AddField( + model_name='tag', + name='name_fi', + field=models.CharField(max_length=127, null=True), + ), + ] diff --git a/webapp/models.py b/webapp/models.py index ccf5014..8678d45 100644 --- a/webapp/models.py +++ b/webapp/models.py @@ -1,37 +1,32 @@ from django.db import models from django.utils import timezone - +from datetime import timedelta +from django.contrib.auth.models import User +from webapp.utils import month_from_now class Tag(models.Model): - # ALWAYS USE TRANSLATED NAME!!! - dummyname = models.CharField(max_length=127) - - -class TagTr(models.Model): - ''' - Model containing translations for tags - ''' - lang = models.CharField(max_length=2, default='fi') + slug = models.SlugField(primary_key=True) name = models.CharField(max_length=127) - translation_for = models.ForeignKey('Tag', related_name='translations') + icon = models.ImageField() -class Info(models.Model): +class BaseFeed(models.Model): ''' model containing something showing on some info feed ''' - publish_time = models.DateTimeField(default=timezone.now) - - # published_by = models.Foreignkey(User) #<-- TODO create usermodel - tags = models.ManyToManyField(Tag, related_name="news") - - -class InfoTr(models.Model): - ''' - Model containing translations for news - ''' - lang = models.CharField(max_length=2, default='fi') - - topic = models.CharField(max_length=255) + tags = models.ManyToManyField(Tag, related_name="feeds", blank=True) + visible = models.BooleanField(default=True) + title = models.CharField(max_length=255) + description = models.CharField(max_length=255) content = models.TextField() - translation_for = models.ForeignKey('Info', related_name='translations') + + +class Feed(BaseFeed): + + publish_time = models.DateTimeField(default=timezone.now) + autohide = models.DateTimeField(default=month_from_now) + + +class Event(BaseFeed): + start_time = models.DateTimeField(default=timezone.now) + end_time = models.DateTimeField(default=timezone.now) diff --git a/webapp/translation.py b/webapp/translation.py new file mode 100644 index 0000000..fb69587 --- /dev/null +++ b/webapp/translation.py @@ -0,0 +1,19 @@ +from modeltranslation.translator import register, TranslationOptions +from webapp.models import BaseFeed, Feed, Tag, Event + +@register(BaseFeed) +class BaseFeedTranslationOptions(TranslationOptions): + fields = ('title', 'description', 'content') + +@register(Feed) +class FeedTranslationOptions(TranslationOptions): + fields = () + +@register(Event) +class EventTranslationOptions(TranslationOptions): + fields = () + + +@register(Tag) +class TagTranslationOptions(TranslationOptions): + fields = ('name',) diff --git a/webapp/utils.py b/webapp/utils.py new file mode 100644 index 0000000..0886e08 --- /dev/null +++ b/webapp/utils.py @@ -0,0 +1,6 @@ +from django.utils import timezone +from datetime import timedelta + + +def month_from_now(): + return timezone.now() + timedelta(days=30) From 543d4321544c3e4a570a7154e1d2ecc5e889deba Mon Sep 17 00:00:00 2001 From: Joel Lavikainen Date: Wed, 7 Jun 2017 19:14:57 +0300 Subject: [PATCH 05/39] Add kaehmyform and message --- webapp/models.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/webapp/models.py b/webapp/models.py index aae924e..d314415 100644 --- a/webapp/models.py +++ b/webapp/models.py @@ -51,13 +51,42 @@ class PresetRole(BaseRole): summary = models.TextField(_('Summary')) -class CustomRole(BaseRole): +class PresetKaehmyRole(PresetRole): + form = models.ForeignKey('KaehmyForm', related_name='preset_roles') + + +class CustomKaehmyRole(BaseRole): ''' Model representing a user-specified custom occupation ''' + form = models.ForeignKey('KaehmyForm', related_name='custom_roles') + + +class MessageParent(models.Model): pass +class KaehmyMessage(MessageParent): + ''' + Model representing a kaehmymessage. + Every message relates to certain kaehmyform or parent message. + ''' + name = models.TextField(_('Name')) + email = models.EmailField(_('Email')) + message = models.TextField(_('Message')) + parent = models.ForeignKey('MessageParent', related_name='messages') + + +class KaehmyForm(MessageParent): + ''' + Model representing a form for kaehmy. + Allows user to choose from existing roles or to create custom ones. + ''' + name = models.TextField(_('Name')) + email = models.EmailField(_('Email')) + year = models.IntegerField(_('Year')) + + class Role(PresetRole): ''' Model representing an active or historical occupation From 81deba547262e3b716a99d7f79c649d163c0ec11 Mon Sep 17 00:00:00 2001 From: Joel Lavikainen Date: Wed, 7 Jun 2017 19:21:28 +0300 Subject: [PATCH 06/39] Add kaehmy models to admin --- webapp/admin.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/webapp/admin.py b/webapp/admin.py index 11f6e98..6317cc3 100644 --- a/webapp/admin.py +++ b/webapp/admin.py @@ -1,6 +1,8 @@ from django.contrib import admin from webapp.models import Official, Role from webapp.models import Feed, Tag, BaseFeed, Event +from webapp.models import KaehmyForm, KaehmyMessage +from webapp.models import CustomKaehmyRole, PresetKaehmyRole from modeltranslation.admin import TranslationAdmin @@ -9,3 +11,7 @@ admin.site.register(Tag, TranslationAdmin) admin.site.register(Event, TranslationAdmin) admin.site.register(Official) admin.site.register(Role) +admin.site.register(KaehmyForm) +admin.site.register(KaehmyMessage) +admin.site.register(CustomKaehmyRole) +admin.site.register(PresetKaehmyRole) From 94c2c16874c068334a14c59277dff3fb8c2bd527 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Thu, 8 Jun 2017 09:25:03 +0300 Subject: [PATCH 07/39] Add missing migrations --- webapp/migrations/0010_auto_20170608_0924.py | 74 ++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 webapp/migrations/0010_auto_20170608_0924.py diff --git a/webapp/migrations/0010_auto_20170608_0924.py b/webapp/migrations/0010_auto_20170608_0924.py new file mode 100644 index 0000000..5939260 --- /dev/null +++ b/webapp/migrations/0010_auto_20170608_0924.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-06-08 06:24 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapp', '0009_merge_20170607_1854'), + ] + + operations = [ + migrations.CreateModel( + name='CustomKaehmyRole', + fields=[ + ('baserole_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='webapp.BaseRole')), + ], + bases=('webapp.baserole',), + ), + migrations.CreateModel( + name='MessageParent', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + ), + migrations.CreateModel( + name='PresetKaehmyRole', + fields=[ + ('presetrole_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='webapp.PresetRole')), + ], + bases=('webapp.presetrole',), + ), + migrations.RemoveField( + model_name='customrole', + name='baserole_ptr', + ), + migrations.CreateModel( + name='KaehmyForm', + fields=[ + ('messageparent_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='webapp.MessageParent')), + ('name', models.TextField(verbose_name='Name')), + ('email', models.EmailField(max_length=254, verbose_name='Email')), + ('year', models.IntegerField(verbose_name='Year')), + ], + bases=('webapp.messageparent',), + ), + migrations.CreateModel( + name='KaehmyMessage', + fields=[ + ('messageparent_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='webapp.MessageParent')), + ('name', models.TextField(verbose_name='Name')), + ('email', models.EmailField(max_length=254, verbose_name='Email')), + ('message', models.TextField(verbose_name='Message')), + ('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='messages', to='webapp.MessageParent')), + ], + bases=('webapp.messageparent',), + ), + migrations.DeleteModel( + name='CustomRole', + ), + migrations.AddField( + model_name='presetkaehmyrole', + name='form', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='preset_roles', to='webapp.KaehmyForm'), + ), + migrations.AddField( + model_name='customkaehmyrole', + name='form', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='custom_roles', to='webapp.KaehmyForm'), + ), + ] From cc3564bf42a70b7c16f41954ac3c81594ce9a7f3 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Thu, 8 Jun 2017 09:29:27 +0300 Subject: [PATCH 08/39] Fix pep8 errors --- webapp/__init__.py | 1 - webapp/translation.py | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/webapp/__init__.py b/webapp/__init__.py index 8b13789..e69de29 100644 --- a/webapp/__init__.py +++ b/webapp/__init__.py @@ -1 +0,0 @@ - diff --git a/webapp/translation.py b/webapp/translation.py index fb69587..678be16 100644 --- a/webapp/translation.py +++ b/webapp/translation.py @@ -1,14 +1,17 @@ from modeltranslation.translator import register, TranslationOptions from webapp.models import BaseFeed, Feed, Tag, Event + @register(BaseFeed) class BaseFeedTranslationOptions(TranslationOptions): fields = ('title', 'description', 'content') + @register(Feed) class FeedTranslationOptions(TranslationOptions): fields = () + @register(Event) class EventTranslationOptions(TranslationOptions): fields = () From c9aef9dba4dfc6aa8d75237e85c1fe18eace66fb Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Thu, 15 Jun 2017 19:32:17 +0300 Subject: [PATCH 09/39] Created audit log models --- webapp/migrations/0011_auto_20170615_1924.py | 68 ++++++++++++++++++++ webapp/models.py | 28 ++++++-- 2 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 webapp/migrations/0011_auto_20170615_1924.py diff --git a/webapp/migrations/0011_auto_20170615_1924.py b/webapp/migrations/0011_auto_20170615_1924.py new file mode 100644 index 0000000..2aa72c3 --- /dev/null +++ b/webapp/migrations/0011_auto_20170615_1924.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-06-15 16:24 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapp', '0010_auto_20170608_0924'), + ] + + operations = [ + migrations.CreateModel( + name='AuditedModel', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ], + ), + migrations.CreateModel( + name='AuditLogEntry', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateTimeField(default=django.utils.timezone.now)), + ('event', models.CharField(choices=[('CREATED', 'Created'), ('MODIFIED', 'Modified'), ('DELETED', 'Deleted')], max_length=10)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='webapp.Official')), + ], + ), + migrations.RemoveField( + model_name='basefeed', + name='id', + ), + migrations.RemoveField( + model_name='baserole', + name='id', + ), + migrations.RemoveField( + model_name='messageparent', + name='id', + ), + migrations.AddField( + model_name='basefeed', + name='auditedmodel_ptr', + field=models.OneToOneField(auto_created=True, default=1, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='webapp.AuditedModel'), + preserve_default=False, + ), + migrations.AddField( + model_name='baserole', + name='auditedmodel_ptr', + field=models.OneToOneField(auto_created=True, default=1, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='webapp.AuditedModel'), + preserve_default=False, + ), + migrations.AddField( + model_name='messageparent', + name='auditedmodel_ptr', + field=models.OneToOneField(auto_created=True, default=1, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='webapp.AuditedModel'), + preserve_default=False, + ), + migrations.AddField( + model_name='tag', + name='auditedmodel_ptr', + field=models.OneToOneField(auto_created=True, default=1, on_delete=django.db.models.deletion.CASCADE, parent_link=True, to='webapp.AuditedModel'), + preserve_default=False, + ), + ] diff --git a/webapp/models.py b/webapp/models.py index d314415..040610e 100644 --- a/webapp/models.py +++ b/webapp/models.py @@ -7,13 +7,33 @@ from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User -class Tag(models.Model): +class AuditLogEntry(models.Model): + ''' + A single entry in the audit log + ''' + user = models.ForeignKey('Official') + date = models.DateTimeField(default=timezone.now) + event = models.CharField(choices=[ + ('CREATED', _('Created')), + ('MODIFIED', _('Modified')), + ('DELETED', _('Deleted'))], + max_length=10) + + +class AuditedModel(models.Model): + ''' + Superclass for all audited models, e.g. events + ''' + pass + + +class Tag(AuditedModel): slug = models.SlugField(primary_key=True) name = models.CharField(max_length=127) icon = models.ImageField() -class BaseFeed(models.Model): +class BaseFeed(AuditedModel): ''' model containing something showing on some info feed ''' @@ -35,7 +55,7 @@ class Event(BaseFeed): end_time = models.DateTimeField(default=timezone.now) -class BaseRole(models.Model): +class BaseRole(AuditedModel): ''' Base model for occupations/roles ''' @@ -62,7 +82,7 @@ class CustomKaehmyRole(BaseRole): form = models.ForeignKey('KaehmyForm', related_name='custom_roles') -class MessageParent(models.Model): +class MessageParent(AuditedModel): pass From 4f62dce814db56c5a4844e74246278530e4dfc60 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Sat, 17 Jun 2017 13:47:31 +0300 Subject: [PATCH 10/39] Use django-auditlog :smirk: --- requirements.txt | 1 + sikweb/settings-sample.py | 2 + webapp/migrations/0011_auto_20170615_1924.py | 68 -------------------- webapp/models.py | 37 ++++------- 4 files changed, 16 insertions(+), 92 deletions(-) delete mode 100644 webapp/migrations/0011_auto_20170615_1924.py diff --git a/requirements.txt b/requirements.txt index f9329ef..72e3e6d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,3 +24,4 @@ django-tables2==1.6.1 pep8==1.7.0 dealer==2.0.5 django-modeltranslation==0.12.1 +django-auditlog==0.4.3 diff --git a/sikweb/settings-sample.py b/sikweb/settings-sample.py index 40ec433..d775560 100644 --- a/sikweb/settings-sample.py +++ b/sikweb/settings-sample.py @@ -50,6 +50,7 @@ INSTALLED_APPS = [ 'django_nose', 'bootstrap3', 'django_tables2', + 'auditlog' ] TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' @@ -73,6 +74,7 @@ MIDDLEWARE_CLASSES = [ 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'auditlog.middleware.AuditlogMiddleware' ] CORS_ORIGIN_ALLOW_ALL = True diff --git a/webapp/migrations/0011_auto_20170615_1924.py b/webapp/migrations/0011_auto_20170615_1924.py deleted file mode 100644 index 2aa72c3..0000000 --- a/webapp/migrations/0011_auto_20170615_1924.py +++ /dev/null @@ -1,68 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11 on 2017-06-15 16:24 -from __future__ import unicode_literals - -from django.db import migrations, models -import django.db.models.deletion -import django.utils.timezone - - -class Migration(migrations.Migration): - - dependencies = [ - ('webapp', '0010_auto_20170608_0924'), - ] - - operations = [ - migrations.CreateModel( - name='AuditedModel', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ], - ), - migrations.CreateModel( - name='AuditLogEntry', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('date', models.DateTimeField(default=django.utils.timezone.now)), - ('event', models.CharField(choices=[('CREATED', 'Created'), ('MODIFIED', 'Modified'), ('DELETED', 'Deleted')], max_length=10)), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='webapp.Official')), - ], - ), - migrations.RemoveField( - model_name='basefeed', - name='id', - ), - migrations.RemoveField( - model_name='baserole', - name='id', - ), - migrations.RemoveField( - model_name='messageparent', - name='id', - ), - migrations.AddField( - model_name='basefeed', - name='auditedmodel_ptr', - field=models.OneToOneField(auto_created=True, default=1, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='webapp.AuditedModel'), - preserve_default=False, - ), - migrations.AddField( - model_name='baserole', - name='auditedmodel_ptr', - field=models.OneToOneField(auto_created=True, default=1, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='webapp.AuditedModel'), - preserve_default=False, - ), - migrations.AddField( - model_name='messageparent', - name='auditedmodel_ptr', - field=models.OneToOneField(auto_created=True, default=1, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='webapp.AuditedModel'), - preserve_default=False, - ), - migrations.AddField( - model_name='tag', - name='auditedmodel_ptr', - field=models.OneToOneField(auto_created=True, default=1, on_delete=django.db.models.deletion.CASCADE, parent_link=True, to='webapp.AuditedModel'), - preserve_default=False, - ), - ] diff --git a/webapp/models.py b/webapp/models.py index 040610e..b7ac62f 100644 --- a/webapp/models.py +++ b/webapp/models.py @@ -5,35 +5,16 @@ from django.contrib.auth.models import User from webapp.utils import month_from_now from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User +from auditlog.registry import auditlog -class AuditLogEntry(models.Model): - ''' - A single entry in the audit log - ''' - user = models.ForeignKey('Official') - date = models.DateTimeField(default=timezone.now) - event = models.CharField(choices=[ - ('CREATED', _('Created')), - ('MODIFIED', _('Modified')), - ('DELETED', _('Deleted'))], - max_length=10) - - -class AuditedModel(models.Model): - ''' - Superclass for all audited models, e.g. events - ''' - pass - - -class Tag(AuditedModel): +class Tag(models.Model): slug = models.SlugField(primary_key=True) name = models.CharField(max_length=127) icon = models.ImageField() -class BaseFeed(AuditedModel): +class BaseFeed(models.Model): ''' model containing something showing on some info feed ''' @@ -55,7 +36,7 @@ class Event(BaseFeed): end_time = models.DateTimeField(default=timezone.now) -class BaseRole(AuditedModel): +class BaseRole(models.Model): ''' Base model for occupations/roles ''' @@ -82,7 +63,7 @@ class CustomKaehmyRole(BaseRole): form = models.ForeignKey('KaehmyForm', related_name='custom_roles') -class MessageParent(AuditedModel): +class MessageParent(models.Model): pass @@ -128,3 +109,11 @@ class Official(User): verbose_name = _('Official') phone_number = models.TextField(_('Phone number')) + + +auditlog.register(Tag) +auditlog.register(Feed) +auditlog.register(Event) +auditlog.register(PresetRole) +auditlog.register(Role) +auditlog.register(Official) From d438c7b16a188933a2b4d042baeafd8416619fb9 Mon Sep 17 00:00:00 2001 From: Aarni Date: Wed, 13 Sep 2017 18:44:17 +0300 Subject: [PATCH 11/39] Use more appropriate fields instead of TextFields Fix issue #72 --- .../migrations/0005_auto_20170913_1841.py | 25 +++++++++++++ infoscreen/models.py | 4 +-- requirements.txt | 1 + sikweb/settings-sample.py | 3 +- webapp/migrations/0011_auto_20170913_1841.py | 36 +++++++++++++++++++ webapp/models.py | 9 ++--- 6 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 infoscreen/migrations/0005_auto_20170913_1841.py create mode 100644 webapp/migrations/0011_auto_20170913_1841.py diff --git a/infoscreen/migrations/0005_auto_20170913_1841.py b/infoscreen/migrations/0005_auto_20170913_1841.py new file mode 100644 index 0000000..d23b561 --- /dev/null +++ b/infoscreen/migrations/0005_auto_20170913_1841.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-09-13 15:41 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('infoscreen', '0004_videoinfoitem'), + ] + + operations = [ + migrations.AlterField( + model_name='externalimageinfoitem', + name='url', + field=models.URLField(), + ), + migrations.AlterField( + model_name='externalwebsiteinfoitem', + name='url', + field=models.URLField(), + ), + ] diff --git a/infoscreen/models.py b/infoscreen/models.py index def1096..5f47cc5 100644 --- a/infoscreen/models.py +++ b/infoscreen/models.py @@ -97,7 +97,7 @@ class ApyInfoItem(InfoItem): class ExternalWebsiteInfoItem(InfoItem): display_name = _("External website") - url = models.TextField() + url = models.URLField() def get_template_url(self): return "/static/html/external_website.html?url={}".format(self.name) @@ -213,7 +213,7 @@ class HslInfoItem(InfoItem): class ExternalImageInfoItem(InfoItem): display_name = _("External image") - url = models.TextField() + url = models.URLField() def get_template_url(self): return "/static/html/generic_image.html?img={}".format(self.name) diff --git a/requirements.txt b/requirements.txt index 72e3e6d..434a845 100644 --- a/requirements.txt +++ b/requirements.txt @@ -25,3 +25,4 @@ pep8==1.7.0 dealer==2.0.5 django-modeltranslation==0.12.1 django-auditlog==0.4.3 +django-phonenumber-field==1.3.0 diff --git a/sikweb/settings-sample.py b/sikweb/settings-sample.py index d775560..a7fe312 100644 --- a/sikweb/settings-sample.py +++ b/sikweb/settings-sample.py @@ -50,7 +50,8 @@ INSTALLED_APPS = [ 'django_nose', 'bootstrap3', 'django_tables2', - 'auditlog' + 'auditlog', + 'phonenumber_field', ] TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' diff --git a/webapp/migrations/0011_auto_20170913_1841.py b/webapp/migrations/0011_auto_20170913_1841.py new file mode 100644 index 0000000..74d06f5 --- /dev/null +++ b/webapp/migrations/0011_auto_20170913_1841.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2017-09-13 15:41 +from __future__ import unicode_literals + +from django.db import migrations, models +import phonenumber_field.modelfields + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapp', '0010_auto_20170608_0924'), + ] + + operations = [ + migrations.AlterField( + model_name='baserole', + name='name', + field=models.CharField(max_length=256, verbose_name='Name'), + ), + migrations.AlterField( + model_name='kaehmyform', + name='name', + field=models.CharField(max_length=256, verbose_name='Name'), + ), + migrations.AlterField( + model_name='kaehmymessage', + name='name', + field=models.CharField(max_length=256, verbose_name='Name'), + ), + migrations.AlterField( + model_name='official', + name='phone_number', + field=phonenumber_field.modelfields.PhoneNumberField(max_length=128, verbose_name='Phone number'), + ), + ] diff --git a/webapp/models.py b/webapp/models.py index b7ac62f..993702d 100644 --- a/webapp/models.py +++ b/webapp/models.py @@ -6,6 +6,7 @@ from webapp.utils import month_from_now from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User from auditlog.registry import auditlog +from phonenumber_field.modelfields import PhoneNumberField class Tag(models.Model): @@ -40,7 +41,7 @@ class BaseRole(models.Model): ''' Base model for occupations/roles ''' - name = models.TextField(_('Name')) + name = models.CharField(_('Name'), max_length=256) is_board = models.BooleanField(_('Board member')) @@ -72,7 +73,7 @@ class KaehmyMessage(MessageParent): Model representing a kaehmymessage. Every message relates to certain kaehmyform or parent message. ''' - name = models.TextField(_('Name')) + name = models.CharField(_('Name'), max_length=256) email = models.EmailField(_('Email')) message = models.TextField(_('Message')) parent = models.ForeignKey('MessageParent', related_name='messages') @@ -83,7 +84,7 @@ class KaehmyForm(MessageParent): Model representing a form for kaehmy. Allows user to choose from existing roles or to create custom ones. ''' - name = models.TextField(_('Name')) + name = models.CharField(_('Name'), max_length=256) email = models.EmailField(_('Email')) year = models.IntegerField(_('Year')) @@ -108,7 +109,7 @@ class Official(User): class Meta: verbose_name = _('Official') - phone_number = models.TextField(_('Phone number')) + phone_number = PhoneNumberField(_('Phone number')) auditlog.register(Tag) From b16bef536e68ab237383a2920d0766701f538a29 Mon Sep 17 00:00:00 2001 From: Juhana Luomanen Date: Wed, 13 Sep 2017 19:42:45 +0300 Subject: [PATCH 12/39] Fix admin site header. Resolve issue #71 --- members/admin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/members/admin.py b/members/admin.py index 2251173..b150c1d 100644 --- a/members/admin.py +++ b/members/admin.py @@ -6,3 +6,5 @@ admin.site.register(Member) admin.site.register(Request) admin.site.register(Payment) admin.site.register(MemberConflict) + +admin.site.site_header = 'SIK Admin' From 41c9aab5956e7f4b64253b9daf86ff06d3e192fd Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Thu, 14 Sep 2017 15:55:39 +0300 Subject: [PATCH 13/39] Add automatic deployment --- .gitlab-ci.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ea79d70..b7f7df0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,6 +11,7 @@ variables: stages: - test - lint + - deploy test: stage: test @@ -37,3 +38,19 @@ eslint: script: - npm install -g eslint - eslint . + +deploy: + stage: deploy + environment: + name: dev + url: http://web.sik.party + only: + - develop + script: + - python -V + - pip install -r requirements.txt + - cp sikweb/settings-sample.py sikweb/default_settings.py + - cp sikweb/.ci-settings.py sikweb/settings.py + - python manage.py migrate --noinput + - python manage.py createdefaultadmin + - python manage.py runserver 0.0.0.0:8080 From 2c9c1a76c839c96dd67125e7ee06dcdf21c29746 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Thu, 14 Sep 2017 19:25:45 +0300 Subject: [PATCH 14/39] Remove runserver from deploy config --- .gitlab-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b7f7df0..9db96de 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -53,4 +53,3 @@ deploy: - cp sikweb/.ci-settings.py sikweb/settings.py - python manage.py migrate --noinput - python manage.py createdefaultadmin - - python manage.py runserver 0.0.0.0:8080 From b0235d60892182d7e558378060fefa531369b6ab Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 15:40:17 +0300 Subject: [PATCH 15/39] Add deployment stuffs --- .gitlab-ci.yml | 17 +++-- .wait-for-it.sh | 177 +++++++++++++++++++++++++++++++++++++++++++++ Dockerfile | 9 +++ docker-compose.yml | 15 ++++ setup.sh | 18 +++-- 5 files changed, 226 insertions(+), 10 deletions(-) create mode 100755 .wait-for-it.sh create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9db96de..16898a7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -46,10 +46,17 @@ deploy: url: http://web.sik.party only: - develop + before_script: + - # Install ssh-agent if not already installed, it is required by Docker. + - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' + - eval $(ssh-agent -s) + - ssh-add <(echo "$SSH_PRIVATE_KEY") + - mkdir -p ~/.ssh + - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' script: - python -V - - pip install -r requirements.txt - - cp sikweb/settings-sample.py sikweb/default_settings.py - - cp sikweb/.ci-settings.py sikweb/settings.py - - python manage.py migrate --noinput - - python manage.py createdefaultadmin + - docker-compose build + - docker-compose push + - scp docker-compose.yaml $SSH_USER@web.sik.party:~/deployment/ + - ssh $SSH_USER@web.sik.party 'cd deployment && docker-compose pull web20:latest && docker-compose up -d' + diff --git a/.wait-for-it.sh b/.wait-for-it.sh new file mode 100755 index 0000000..bbe4043 --- /dev/null +++ b/.wait-for-it.sh @@ -0,0 +1,177 @@ +#!/usr/bin/env bash +# Use this script to test if a given TCP host/port are available + +cmdname=$(basename $0) + +echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } + +usage() +{ + cat << USAGE >&2 +Usage: + $cmdname host:port [-s] [-t timeout] [-- command args] + -h HOST | --host=HOST Host or IP under test + -p PORT | --port=PORT TCP port under test + Alternatively, you specify the host and port as host:port + -s | --strict Only execute subcommand if the test succeeds + -q | --quiet Don't output any status messages + -t TIMEOUT | --timeout=TIMEOUT + Timeout in seconds, zero for no timeout + -- COMMAND ARGS Execute command with args after the test finishes +USAGE + exit 1 +} + +wait_for() +{ + if [[ $TIMEOUT -gt 0 ]]; then + echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT" + else + echoerr "$cmdname: waiting for $HOST:$PORT without a timeout" + fi + start_ts=$(date +%s) + while : + do + if [[ $ISBUSY -eq 1 ]]; then + nc -z $HOST $PORT + result=$? + else + (echo > /dev/tcp/$HOST/$PORT) >/dev/null 2>&1 + result=$? + fi + if [[ $result -eq 0 ]]; then + end_ts=$(date +%s) + echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds" + break + fi + sleep 1 + done + return $result +} + +wait_for_wrapper() +{ + # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 + if [[ $QUIET -eq 1 ]]; then + timeout $BUSYTIMEFLAG $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & + else + timeout $BUSYTIMEFLAG $TIMEOUT $0 --child --host=$HOST --port=$PORT --timeout=$TIMEOUT & + fi + PID=$! + trap "kill -INT -$PID" INT + wait $PID + RESULT=$? + if [[ $RESULT -ne 0 ]]; then + echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT" + fi + return $RESULT +} + +# process arguments +while [[ $# -gt 0 ]] +do + case "$1" in + *:* ) + hostport=(${1//:/ }) + HOST=${hostport[0]} + PORT=${hostport[1]} + shift 1 + ;; + --child) + CHILD=1 + shift 1 + ;; + -q | --quiet) + QUIET=1 + shift 1 + ;; + -s | --strict) + STRICT=1 + shift 1 + ;; + -h) + HOST="$2" + if [[ $HOST == "" ]]; then break; fi + shift 2 + ;; + --host=*) + HOST="${1#*=}" + shift 1 + ;; + -p) + PORT="$2" + if [[ $PORT == "" ]]; then break; fi + shift 2 + ;; + --port=*) + PORT="${1#*=}" + shift 1 + ;; + -t) + TIMEOUT="$2" + if [[ $TIMEOUT == "" ]]; then break; fi + shift 2 + ;; + --timeout=*) + TIMEOUT="${1#*=}" + shift 1 + ;; + --) + shift + CLI=("$@") + break + ;; + --help) + usage + ;; + *) + echoerr "Unknown argument: $1" + usage + ;; + esac +done + +if [[ "$HOST" == "" || "$PORT" == "" ]]; then + echoerr "Error: you need to provide a host and port to test." + usage +fi + +TIMEOUT=${TIMEOUT:-15} +STRICT=${STRICT:-0} +CHILD=${CHILD:-0} +QUIET=${QUIET:-0} + +# check to see if timeout is from busybox? +# check to see if timeout is from busybox? +TIMEOUT_PATH=$(realpath $(which timeout)) +if [[ $TIMEOUT_PATH =~ "busybox" ]]; then + ISBUSY=1 + BUSYTIMEFLAG="-t" +else + ISBUSY=0 + BUSYTIMEFLAG="" +fi + +if [[ $CHILD -gt 0 ]]; then + wait_for + RESULT=$? + exit $RESULT +else + if [[ $TIMEOUT -gt 0 ]]; then + wait_for_wrapper + RESULT=$? + else + wait_for + RESULT=$? + fi +fi + +if [[ $CLI != "" ]]; then + if [[ $RESULT -ne 0 && $STRICT -eq 1 ]]; then + echoerr "$cmdname: strict mode, refusing to execute subprocess" + exit $RESULT + fi + exec "${CLI[@]}" +else + exit $RESULT +fi diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6f87337 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM python:3 +ENV PYTHONUNBUFFERED 1 +ENV IS_DOCKER 1 +RUN mkdir /code +WORKDIR /code +ADD requirements.txt /code/ +RUN env +RUN pip install -r requirements.txt +ADD . /code/ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..cf9ed4c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3' + +services: + db: + image: postgres + web: + build: . + image: 86.50.143.82:5000/web20 + command: ["bash", "-c", "./.wait-for-it.sh db:5432 -- bash setup.py --no-input"] + volumes: + - .:/code + ports: + - "8080:8080" + depends_on: + - db diff --git a/setup.sh b/setup.sh index 15aba08..1e295e3 100755 --- a/setup.sh +++ b/setup.sh @@ -5,7 +5,13 @@ echo "This script will set up the environment for this project." echo "=========================================================" echo "Dependencies: postgresql>9.5, python>3.5" -read -p "Are these programs installed? [y/n]" -n 1 -r +INTERACTIVE="true" +if [[ $* == *--no-input* ]] +then + INTERACTIVE="false" +fi + +$INTERACTIVE && read -p "Are these programs installed? [y/n]" -n 1 -r || REPLY="y" echo "" if [[ ! $REPLY =~ ^[Yy]$ ]] @@ -14,7 +20,7 @@ then exit 0 fi -read -p "Create user 'sik' in postgres (needs sudo) [y/n]?" -n 1 -r +$INTERACTIVE && read -p "Create user 'sik' in postgres (needs sudo) [y/n]?" -n 1 -r || REPLY="n" echo "" if [[ $REPLY =~ ^[Yy]$ ]] @@ -22,7 +28,7 @@ then sudo -u postgres psql < "$PWD/scripts/db/init.sql" fi -read -p "Is virtualenv activated? [y/n]" -n 1 -r +$INTERACTIVE && read -p "Is virtualenv activated? [y/n]" -n 1 -r || REPLY="y" echo "" if [[ ! $REPLY =~ ^[Yy]$ ]] @@ -31,7 +37,7 @@ then exit 0 fi -read -p "Copy settings from template? [y/n]" -n 1 -r +$INTERACTIVE && read -p "Copy settings from template? [y/n]" -n 1 -r || REPLY="y" echo "" if [[ $REPLY =~ ^[Yy]$ ]] @@ -40,7 +46,7 @@ then fi -read -p "Start setup? [y/n]" -n 1 -r +$INTERACTIVE && read -p "Start setup? [y/n]" -n 1 -r || REPLY="y" echo "" if [[ ! $REPLY =~ ^[Yy]$ ]] @@ -49,10 +55,12 @@ then exit 0 fi +set -e (set -x; pip install -r requirements.txt) (set -x; npm install) (set -x; python manage.py migrate) (set -x; python manage.py createdefaultadmin) +set +e echo "Done." echo "Run 'python manage.py runserver 0.0.0.0:8000' to start the development server!" From 5e989321329f44ea63534b37e42c491dcd824b79 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 15:42:48 +0300 Subject: [PATCH 16/39] Fix .gitlab-ci.yml --- .gitlab-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 16898a7..d502622 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,7 +47,6 @@ deploy: only: - develop before_script: - - # Install ssh-agent if not already installed, it is required by Docker. - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' - eval $(ssh-agent -s) - ssh-add <(echo "$SSH_PRIVATE_KEY") From 26ee4bbfea9790384d4a60cec6a57ef3c4de5b66 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 15:52:55 +0300 Subject: [PATCH 17/39] Add docker-compose to CI --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d502622..4008b87 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -52,6 +52,8 @@ deploy: - ssh-add <(echo "$SSH_PRIVATE_KEY") - mkdir -p ~/.ssh - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' + - curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose + - chmod a+x /usr/local/bin/docker-compose script: - python -V - docker-compose build From 1dfa7ae3526fcb0ea2cfdaef3a51629e9c652285 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 16:02:35 +0300 Subject: [PATCH 18/39] Add docker installation to CI --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4008b87..824194b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,6 +47,7 @@ deploy: only: - develop before_script: + - curl -fsSL get.docker.com | sh - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' - eval $(ssh-agent -s) - ssh-add <(echo "$SSH_PRIVATE_KEY") From 54090c9cb0fc6a73e1de43048110b2d65853d145 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 16:29:33 +0300 Subject: [PATCH 19/39] Let's try this again --- .gitlab-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 824194b..4008b87 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,7 +47,6 @@ deploy: only: - develop before_script: - - curl -fsSL get.docker.com | sh - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' - eval $(ssh-agent -s) - ssh-add <(echo "$SSH_PRIVATE_KEY") From e5d2520454cc0d32747e52f7746af45659b87523 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 16:31:15 +0300 Subject: [PATCH 20/39] Add dind service --- .gitlab-ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4008b87..71e8d03 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -46,7 +46,12 @@ deploy: url: http://web.sik.party only: - develop + variables: + DOCKER_DRIVER: overlay2 + services: + - docker:dind before_script: + - docker info - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' - eval $(ssh-agent -s) - ssh-add <(echo "$SSH_PRIVATE_KEY") From 150c52a0fb423af2c48b8f2142c7564df441649a Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 16:45:51 +0300 Subject: [PATCH 21/39] Add docker image to deploy stage --- .gitlab-ci.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 71e8d03..bde7784 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -41,15 +41,12 @@ eslint: deploy: stage: deploy + image: docker:latest environment: name: dev url: http://web.sik.party only: - develop - variables: - DOCKER_DRIVER: overlay2 - services: - - docker:dind before_script: - docker info - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' From 04c69995ff649fdca2d69cdef958fdf92884417a Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 17:03:51 +0300 Subject: [PATCH 22/39] Try to fix openssh problems --- .gitlab-ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bde7784..6096a91 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -49,10 +49,8 @@ deploy: - develop before_script: - docker info - - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' - - eval $(ssh-agent -s) - - ssh-add <(echo "$SSH_PRIVATE_KEY") - mkdir -p ~/.ssh + - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' - curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose - chmod a+x /usr/local/bin/docker-compose From 8c71dbe2ed6ea2d940071b1e662c9cf561bc549e Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 17:12:23 +0300 Subject: [PATCH 23/39] Remove curl dependency --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6096a91..64dfb39 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -52,7 +52,7 @@ deploy: - mkdir -p ~/.ssh - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' - - curl -L https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose + - wget https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -O /usr/local/bin/docker-compose - chmod a+x /usr/local/bin/docker-compose script: - python -V From db637453b9fa2700be95f316b3673780c7c0d43d Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 17:27:09 +0300 Subject: [PATCH 24/39] Remove installation of docker-compose from .gitlab-ci.yml --- .gitlab-ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 64dfb39..ae00092 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -52,8 +52,6 @@ deploy: - mkdir -p ~/.ssh - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' - - wget https://github.com/docker/compose/releases/download/1.16.1/docker-compose-`uname -s`-`uname -m` -O /usr/local/bin/docker-compose - - chmod a+x /usr/local/bin/docker-compose script: - python -V - docker-compose build From 34a60e545831d94b99c51756e7dc9670b157f86b Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 17:41:14 +0300 Subject: [PATCH 25/39] Remove brainfart --- .gitlab-ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ae00092..d76c996 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -49,13 +49,15 @@ deploy: - develop before_script: - docker info + - docker-compose --version - mkdir -p ~/.ssh + - echo "$SSH_USER" + - echo "$SSH_PRIVATE_KEY" - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' script: - - python -V - docker-compose build - docker-compose push - - scp docker-compose.yaml $SSH_USER@web.sik.party:~/deployment/ + - scp docker-compose.yml $SSH_USER@web.sik.party:~/deployment/docker-compose.yml - ssh $SSH_USER@web.sik.party 'cd deployment && docker-compose pull web20:latest && docker-compose up -d' From 8f3d10f5d09545d09856d3de9915ab258be35ee4 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 17:58:22 +0300 Subject: [PATCH 26/39] Remove docker-compose dep from CI --- .gitlab-ci.yml | 7 +++---- Dockerfile | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d76c996..9825198 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -49,15 +49,14 @@ deploy: - develop before_script: - docker info - - docker-compose --version - mkdir -p ~/.ssh - echo "$SSH_USER" - echo "$SSH_PRIVATE_KEY" - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' script: - - docker-compose build - - docker-compose push + - docker build -t 86.50.143.82:5000/web20:latest + - docker push 86.50.143.82:5000/web20:latest - scp docker-compose.yml $SSH_USER@web.sik.party:~/deployment/docker-compose.yml - - ssh $SSH_USER@web.sik.party 'cd deployment && docker-compose pull web20:latest && docker-compose up -d' + - ssh $SSH_USER@web.sik.party 'cd deployment && docker-compose down && docker-compose pull web20:latest && docker-compose up -d' diff --git a/Dockerfile b/Dockerfile index 6f87337..cced68f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,5 +5,4 @@ RUN mkdir /code WORKDIR /code ADD requirements.txt /code/ RUN env -RUN pip install -r requirements.txt ADD . /code/ From 880114b214f4257fb50362c787a5b895afa54aed Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 18:05:06 +0300 Subject: [PATCH 27/39] Remove another brainfart --- .gitlab-ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9825198..134084c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -50,12 +50,10 @@ deploy: before_script: - docker info - mkdir -p ~/.ssh - - echo "$SSH_USER" - - echo "$SSH_PRIVATE_KEY" - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' script: - - docker build -t 86.50.143.82:5000/web20:latest + - docker build . -t 86.50.143.82:5000/web20:latest - docker push 86.50.143.82:5000/web20:latest - scp docker-compose.yml $SSH_USER@web.sik.party:~/deployment/docker-compose.yml - ssh $SSH_USER@web.sik.party 'cd deployment && docker-compose down && docker-compose pull web20:latest && docker-compose up -d' From ba795a216269385b09675534434fc4f4c8196fb4 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 18:22:07 +0300 Subject: [PATCH 28/39] Split deploy to stages --- .gitlab-ci.yml | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 134084c..6a9ad72 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -39,22 +39,29 @@ eslint: - npm install -g eslint - eslint . -deploy: +build: stage: deploy image: docker:latest - environment: - name: dev - url: http://web.sik.party only: - develop before_script: - docker info - - mkdir -p ~/.ssh - - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa - - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' script: - docker build . -t 86.50.143.82:5000/web20:latest - docker push 86.50.143.82:5000/web20:latest + +deploy: + stage: deploy + image: alpine:latest + environment: + name: dev + url: http://web.sik.party + before_script: + - ssh -V + script: + - mkdir -p ~/.ssh + - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa + - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' - scp docker-compose.yml $SSH_USER@web.sik.party:~/deployment/docker-compose.yml - ssh $SSH_USER@web.sik.party 'cd deployment && docker-compose down && docker-compose pull web20:latest && docker-compose up -d' From f6afacb93f9200210caa63d4ddb314ce95a7af1c Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 18:32:02 +0300 Subject: [PATCH 29/39] Add ssh client to deploy stage --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6a9ad72..ec9ca8b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -57,6 +57,7 @@ deploy: name: dev url: http://web.sik.party before_script: + - apt-get install -y openssh-client - ssh -V script: - mkdir -p ~/.ssh From ff778d15ee218fca6d470c19461596c9c5353b48 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 18:41:58 +0300 Subject: [PATCH 30/39] Deploy only after publish --- .gitlab-ci.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ec9ca8b..c6583f6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,6 +11,7 @@ variables: stages: - test - lint + - publish - deploy test: @@ -39,8 +40,8 @@ eslint: - npm install -g eslint - eslint . -build: - stage: deploy +publish: + stage: publish image: docker:latest only: - develop @@ -56,8 +57,10 @@ deploy: environment: name: dev url: http://web.sik.party + dependencies: + - publish before_script: - - apt-get install -y openssh-client + - apk add --update openssh - ssh -V script: - mkdir -p ~/.ssh From adb152727e01347abea25d75dd389402fd9dd82a Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 18:50:30 +0300 Subject: [PATCH 31/39] Fix key permission problem --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c6583f6..9a0b45f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -57,15 +57,15 @@ deploy: environment: name: dev url: http://web.sik.party - dependencies: - - publish before_script: + - pwd - apk add --update openssh - ssh -V - script: - mkdir -p ~/.ssh - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' + script: - scp docker-compose.yml $SSH_USER@web.sik.party:~/deployment/docker-compose.yml - ssh $SSH_USER@web.sik.party 'cd deployment && docker-compose down && docker-compose pull web20:latest && docker-compose up -d' From 754f108f573c82ad7aa5eb220483cc21d6d8eb75 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 19:13:17 +0300 Subject: [PATCH 32/39] Add remark --- .gitlab-ci.yml | 35 ++++++++++++++++++++++------------- .remarkignore | 1 + 2 files changed, 23 insertions(+), 13 deletions(-) create mode 100644 .remarkignore diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9a0b45f..d644d26 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,12 +1,5 @@ -image: python:3.5 - -services: - - postgres:latest - variables: - POSTGRES_DB: ci - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres + IMAGE_NAME: "86.50.143.82:5000/web20:latest" stages: - test @@ -15,8 +8,14 @@ stages: - deploy test: + image: python:3.5 stage: test + services: + - postgres:latest variables: + POSTGRES_DB: ci + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/$POSTGRES_DB" script: - python -V @@ -28,6 +27,7 @@ test: - python manage.py test pep8: + image: python:3.5 stage: lint script: - pip install pep8 @@ -36,9 +36,18 @@ pep8: eslint: image: node:7.10.0 stage: lint + before_script: + - npm install script: - - npm install -g eslint - - eslint . + - npm run eslint + +remark: + image: node:7.10.0 + stage: lint + before_script: + - npm install + script: + - npm run remark publish: stage: publish @@ -48,8 +57,8 @@ publish: before_script: - docker info script: - - docker build . -t 86.50.143.82:5000/web20:latest - - docker push 86.50.143.82:5000/web20:latest + - docker build . -t "$IMAGE_NAME" + - docker push "$IMAGE_NAME" deploy: stage: deploy @@ -67,5 +76,5 @@ deploy: - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' script: - scp docker-compose.yml $SSH_USER@web.sik.party:~/deployment/docker-compose.yml - - ssh $SSH_USER@web.sik.party 'cd deployment && docker-compose down && docker-compose pull web20:latest && docker-compose up -d' + - ssh $SSH_USER@web.sik.party 'cd deployment && docker-compose down && docker-compose pull "$IMAGE_NAME" && docker-compose up -d' diff --git a/.remarkignore b/.remarkignore new file mode 100644 index 0000000..c0bcb53 --- /dev/null +++ b/.remarkignore @@ -0,0 +1 @@ +global_static From 8c03fbbca9d25913ae602e5d398147c2d37a2582 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 19:15:49 +0300 Subject: [PATCH 33/39] Commit missing files --- package.json | 11 +++++++++-- readme.md | 32 +++++++++++++++++++++----------- requirements.production.txt | 1 + requirements.txt | 1 - 4 files changed, 31 insertions(+), 14 deletions(-) create mode 100644 requirements.production.txt diff --git a/package.json b/package.json index 330383e..1fe48ae 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,9 @@ "version": "1.0.0", "description": "A modern web app using a Django backend and an Angular frontend.", "scripts": { - "test": "eslint ." + "test": "eslint . && remark .", + "eslint": "eslint .", + "remark": "remark ." }, "repository": { "type": "git", @@ -12,6 +14,11 @@ "author": "SIK ry", "license": "ISC", "dependencies": { - "eslint": "3.19.0" + "eslint": "3.19.0", + "remark-cli": "^4.0.0", + "remark-preset-lint-recommended": "^3.0.1" + }, + "remarkConfig": { + "plugins": ["remark-preset-lint-recommended"] } } diff --git a/readme.md b/readme.md index 03427a4..72b4e75 100644 --- a/readme.md +++ b/readme.md @@ -32,11 +32,11 @@ git checkout develop ### Dependency list -* Python >3.5 -* PostgreSQL >9.5 -* pip3 -* virtualenv -* npm +* Python >3.5 +* PostgreSQL >9.5 +* pip3 +* virtualenv +* npm Install with apt: ``` @@ -48,14 +48,14 @@ sudo apt install npm ``` More info about PostgreSQL at: -https://www.postgresql.org/ +[https://www.postgresql.org/](https://www.postgresql.org) These packages might be needed on certain platforms: -* python3-dev -* libffi-dev -* python3-cffi -* libssl-dev +* python3-dev +* libffi-dev +* python3-cffi +* libssl-dev ## Create a virtual environment for python @@ -94,7 +94,17 @@ Using address 0.0.0.0 will bind to all IP addresses. ### Visit the page -Visit https://localhost:8000 in your browser! +Visit [https://localhost:8000](https://localhost:8000) in your browser! + +## Running in production + +A good way to run django in production is by using uWSGI. Install uWSGI with: + +``` +pip install -r requirements.production.txt +``` + +Create an uWSGI ini file and run the daemon according to online instructions. ## Development workflow diff --git a/requirements.production.txt b/requirements.production.txt new file mode 100644 index 0000000..496884e --- /dev/null +++ b/requirements.production.txt @@ -0,0 +1 @@ +uWSGI==2.0.14 diff --git a/requirements.txt b/requirements.txt index 434a845..ab2442a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,7 +17,6 @@ djangorestframework==3.5.3 coverage==4.3.4 django-nose==1.4.4 nose-exclude==0.5.0 -uWSGI==2.0.14 psycopg2==2.7.1 django-bootstrap3==8.2.3 django-tables2==1.6.1 From 572834f1656f8b7ccc7912d94648cabaee768857 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 19:25:14 +0300 Subject: [PATCH 34/39] Use secret variables in CI jobs --- .gitlab-ci.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d644d26..3a5ebdf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,3 @@ -variables: - IMAGE_NAME: "86.50.143.82:5000/web20:latest" - stages: - test - lint @@ -75,6 +72,5 @@ deploy: - chmod 600 ~/.ssh/id_rsa - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' script: - - scp docker-compose.yml $SSH_USER@web.sik.party:~/deployment/docker-compose.yml - - ssh $SSH_USER@web.sik.party 'cd deployment && docker-compose down && docker-compose pull "$IMAGE_NAME" && docker-compose up -d' - + - scp docker-compose.yml $SSH_USER@$SSH_HOST:~/deployment/docker-compose.yml + - ssh $SSH_USER@$SSH_HOST 'cd deployment && docker-compose down && docker-compose pull "$IMAGE_NAME" && docker-compose up -d' From 84ca0845331c81b7ccd6ca9fe86d8b3f44ab5be8 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 19:31:45 +0300 Subject: [PATCH 35/39] Fuck bash --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3a5ebdf..503f711 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -73,4 +73,4 @@ deploy: - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' script: - scp docker-compose.yml $SSH_USER@$SSH_HOST:~/deployment/docker-compose.yml - - ssh $SSH_USER@$SSH_HOST 'cd deployment && docker-compose down && docker-compose pull "$IMAGE_NAME" && docker-compose up -d' + - ssh $SSH_USER@$SSH_HOST "cd deployment && docker-compose down && docker-compose pull \"$IMAGE_NAME\" && docker-compose up -d" From 12027a5a808634c2dda1c52deb8622756bcc4980 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 20:11:44 +0300 Subject: [PATCH 36/39] Fix things --- docker-compose.yml | 2 +- setup.sh | 17 ++++++++++---- sikweb/settings-sample.py | 39 ++++++++++++++++++++----------- .wait-for-it.sh => wait-for-it.sh | 0 4 files changed, 40 insertions(+), 18 deletions(-) rename .wait-for-it.sh => wait-for-it.sh (100%) diff --git a/docker-compose.yml b/docker-compose.yml index cf9ed4c..3f64c09 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,7 @@ services: web: build: . image: 86.50.143.82:5000/web20 - command: ["bash", "-c", "./.wait-for-it.sh db:5432 -- bash setup.py --no-input"] + command: ["bash", "-c", "cd /code && ./wait-for-it.sh db:5432 -- bash setup.sh --no-input --no-npm && python manage.py runserver 0.0.0.0:8080"] volumes: - .:/code ports: diff --git a/setup.sh b/setup.sh index 1e295e3..8f71754 100755 --- a/setup.sh +++ b/setup.sh @@ -6,10 +6,17 @@ echo "=========================================================" echo "Dependencies: postgresql>9.5, python>3.5" INTERACTIVE="true" +USE_NPM="true" if [[ $* == *--no-input* ]] then INTERACTIVE="false" fi +if [[ $* == *--no-npm* ]] +then + USE_NPM="false" +fi + +$INTERACTIVE || echo "Running in non-interactive mode." && env $INTERACTIVE && read -p "Are these programs installed? [y/n]" -n 1 -r || REPLY="y" echo "" @@ -56,11 +63,13 @@ then fi set -e -(set -x; pip install -r requirements.txt) -(set -x; npm install) -(set -x; python manage.py migrate) -(set -x; python manage.py createdefaultadmin) +set -x +pip install -r requirements.txt +$USE_NPM && npm install +python manage.py migrate +python manage.py createdefaultadmin set +e +set +x echo "Done." echo "Run 'python manage.py runserver 0.0.0.0:8000' to start the development server!" diff --git a/sikweb/settings-sample.py b/sikweb/settings-sample.py index a7fe312..e2fb412 100644 --- a/sikweb/settings-sample.py +++ b/sikweb/settings-sample.py @@ -19,6 +19,7 @@ from django.utils.translation import ugettext_lazy as _ # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +IS_DOCKER = bool(os.getenv('IS_DOCKER', None)) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ @@ -106,20 +107,32 @@ WSGI_APPLICATION = 'sikweb.wsgi.application' # Database # https://docs.djangoproject.com/en/1.9/ref/settings/#databases -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': 'sik', - 'USER': 'sik', - 'PASSWORD': 'password123', - 'HOST': 'localhost', - 'PORT': '5432', - 'TEST': { - 'NAME': 'sik_test', +if not IS_DOCKER: + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': 'sik', + 'USER': 'sik', + 'PASSWORD': 'password123', + 'HOST': 'localhost', + 'PORT': '5432', + 'TEST': { + 'NAME': 'sik_test', + }, }, - }, -} - + } +else: + logging.info('Using docker database configuration') + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': 'postgres', + 'USER': 'postgres', + 'PASSWORD': 'postgres', + 'HOST': 'db', + 'PORT': '5432', + }, + } # Password validation # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators diff --git a/.wait-for-it.sh b/wait-for-it.sh similarity index 100% rename from .wait-for-it.sh rename to wait-for-it.sh From 7e36fd5768ac8668e4682ee834b0c1326b6b940a Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 20:18:22 +0300 Subject: [PATCH 37/39] Change docker-compose pull to docker pull --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 503f711..c1466ab 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -73,4 +73,4 @@ deploy: - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' script: - scp docker-compose.yml $SSH_USER@$SSH_HOST:~/deployment/docker-compose.yml - - ssh $SSH_USER@$SSH_HOST "cd deployment && docker-compose down && docker-compose pull \"$IMAGE_NAME\" && docker-compose up -d" + - ssh $SSH_USER@$SSH_HOST "cd deployment && docker-compose down && docker pull \"$IMAGE_NAME\" && docker-compose up -d" From 040c9641ea8d60d1b91b0e5388155351d567e713 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 20:36:24 +0300 Subject: [PATCH 38/39] Prune old images on deploy host after deployment --- .gitlab-ci.yml | 2 +- docker-compose.yml | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c1466ab..d02d28b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -73,4 +73,4 @@ deploy: - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' script: - scp docker-compose.yml $SSH_USER@$SSH_HOST:~/deployment/docker-compose.yml - - ssh $SSH_USER@$SSH_HOST "cd deployment && docker-compose down && docker pull \"$IMAGE_NAME\" && docker-compose up -d" + - ssh $SSH_USER@$SSH_HOST "cd deployment && docker-compose down && docker pull \"$IMAGE_NAME\" && docker-compose up -d && docker image prune -f" diff --git a/docker-compose.yml b/docker-compose.yml index 3f64c09..507ec1e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,8 +7,6 @@ services: build: . image: 86.50.143.82:5000/web20 command: ["bash", "-c", "cd /code && ./wait-for-it.sh db:5432 -- bash setup.sh --no-input --no-npm && python manage.py runserver 0.0.0.0:8080"] - volumes: - - .:/code ports: - "8080:8080" depends_on: From f800f5c342a43e27025ce84e28b133fb21d892b3 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 15 Sep 2017 20:58:46 +0300 Subject: [PATCH 39/39] Allow all hosts on dev server --- sikweb/settings-sample.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sikweb/settings-sample.py b/sikweb/settings-sample.py index e2fb412..4de7034 100644 --- a/sikweb/settings-sample.py +++ b/sikweb/settings-sample.py @@ -30,7 +30,10 @@ SECRET_KEY = '7p$85^4ibb^p4-=vs44b7!y0e-zemugze18@a#30&71=a8)dp(' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +if not IS_DOCKER: + ALLOWED_HOSTS = [] +else: + ALLOWED_HOSTS = ["*"] # Application definition