Browse Source

Merge pull request #1 from gerrit1986/development

add static files collection explicitly, improve coding style due to flake8, improve readability
Hendrik Sünkler 8 years ago
parent
commit
6394e234e5
7 changed files with 119 additions and 51 deletions
  1. 4
    1
      .gitignore
  2. 4
    3
      README.md
  3. 3
    2
      main/forms.py
  4. 45
    16
      main/models.py
  5. 13
    11
      main/views.py
  6. 9
    6
      tickets/settings.py
  7. 41
    12
      tickets/urls.py

+ 4
- 1
.gitignore View File

@@ -1,6 +1,6 @@
1 1
 # compiled python files
2 2
 *.py[cod]
3
- 
3
+
4 4
 # emacs temp files
5 5
 *~
6 6
 [#]*[#]
@@ -23,3 +23,6 @@ db.sqlite3
23 23
 
24 24
 # bash script to set environment variables
25 25
 env.sh
26
+
27
+# static root folder for local deployments
28
+static_root

+ 4
- 3
README.md View File

@@ -34,7 +34,7 @@ export DJANGO_PRODUCTION_DOMAIN="xxx"
34 34
 export DJANGO_LOG_FILE="xxx"
35 35
 
36 36
 # static and media files dir in production
37
-export DJANGO_STATIC_ROOT="xxx"
37
+export DJANGO_STATIC_ROOT="static_root/"
38 38
 export DJANGO_MEDIA_ROOT="xxx"
39 39
 
40 40
 # User who gets django's email notifications (ADMINS/MANAGERS), see settings.py
@@ -56,7 +56,7 @@ export DJANGO_TICKET_EMAIL_NOTIFICATIONS_FROM="xxx"
56 56
 export DJANGO_TICKET_EMAIL_NOTIFICATIONS_TO="xxx"
57 57
 ```
58 58
 
59
-Please note that `django-tickets` is **not** packaged as a reusable django app; it's a **complete django project**. So just clone the repository and install the dependencies via pip and the application including user authentication is ready to go. 
59
+Please note that `django-tickets` is **not** packaged as a reusable django app; it's a **complete django project**. So just clone the repository and install the dependencies via pip and the application including user authentication is ready to go.
60 60
 
61 61
 ```
62 62
 $ git clone https://github.com/suenkler/django-tickets.git
@@ -64,6 +64,7 @@ $ cd django-tickets
64 64
 $ pip install -r requirements.txt
65 65
 $ source env.sh
66 66
 $ ./manage.py migrate
67
+$ ./manage.py collectstatic
67 68
 $ ./manage.py createsuperuser
68 69
 $ ./manage.py runserver
69 70
 ```
@@ -72,4 +73,4 @@ To check the IMAP account for new messages and create tickets out of these messa
72 73
 
73 74
 ```
74 75
 $ ./manage.py get_email
75
-```
76
+```

+ 3
- 2
main/forms.py View File

@@ -18,11 +18,12 @@ class TicketCreateForm(forms.ModelForm):
18 18
         model = Ticket
19 19
         fields = ('title', 'description')
20 20
 
21
-        
21
+
22 22
 class TicketEditForm(forms.ModelForm):
23 23
     class Meta:
24 24
         model = Ticket
25
-        fields = ('title', 'owner', 'description', 'status', 'waiting_for', 'assigned_to')
25
+        fields = ('title', 'owner', 'description',
26
+                  'status', 'waiting_for', 'assigned_to')
26 27
 
27 28
 
28 29
 class FollowupForm(forms.ModelForm):

+ 45
- 16
main/models.py View File

@@ -13,14 +13,22 @@ def user_unicode(self):
13 13
     """
14 14
     return 'last_name, first_name' for User by default
15 15
     """
16
-    return  u'%s, %s' % (self.last_name, self.first_name)
16
+    return u'%s, %s' % (self.last_name, self.first_name)
17
+
18
+
17 19
 User.__unicode__ = user_unicode
18 20
 
19 21
 
20 22
 class Ticket(models.Model):
21 23
 
22 24
     title = models.CharField('Title', max_length=255)
23
-    owner = models.ForeignKey(User, related_name='owner', blank=True, null=True, verbose_name='Owner', )
25
+
26
+    owner = models.ForeignKey(User,
27
+                              related_name='owner',
28
+                              blank=True,
29
+                              null=True,
30
+                              verbose_name='Owner')
31
+
24 32
     description = models.TextField('Description', blank=True, null=True)
25 33
 
26 34
     STATUS_CHOICES = (
@@ -29,15 +37,26 @@ class Ticket(models.Model):
29 37
         ('WAITING', 'WAITING'),
30 38
         ('DONE', 'DONE'),
31 39
     )
32
-    status = models.CharField('Status', choices=STATUS_CHOICES, max_length=255, blank=True, null=True)
33
-    waiting_for = models.ForeignKey(User, related_name='waiting_for', blank=True, null=True, verbose_name='Waiting For', )
34
-    closed_date = models.DateTimeField(blank=True, null=True)  # set in view when status changed to "DONE"
40
+    status = models.CharField('Status',
41
+                              choices=STATUS_CHOICES,
42
+                              max_length=255,
43
+                              blank=True,
44
+                              null=True)
45
+
46
+    waiting_for = models.ForeignKey(User,
47
+                                    related_name='waiting_for',
48
+                                    blank=True,
49
+                                    null=True,
50
+                                    verbose_name='Waiting For')
51
+
52
+    # set in view when status changed to "DONE"
53
+    closed_date = models.DateTimeField(blank=True, null=True)
35 54
 
36 55
     assigned_to = models.ForeignKey(User,
37 56
                                     related_name='assigned_to',
38 57
                                     blank=True,
39 58
                                     null=True,
40
-                                    verbose_name='Assigned to',)
59
+                                    verbose_name='Assigned to')
41 60
 
42 61
     created = models.DateTimeField(auto_now_add=True)
43 62
     updated = models.DateTimeField(auto_now=True)
@@ -50,11 +69,11 @@ class FollowUp(models.Model):
50 69
     """
51 70
     A FollowUp is a comment to a ticket.
52 71
     """
53
-    ticket = models.ForeignKey(Ticket, verbose_name='Ticket', )
72
+    ticket = models.ForeignKey(Ticket, verbose_name='Ticket')
54 73
     date = models.DateTimeField('Date', default=timezone.now)
55
-    title = models.CharField('Title', max_length=200, )
56
-    text = models.TextField('Text', blank=True, null=True, )
57
-    user = models.ForeignKey(User, blank=True, null=True, verbose_name='User', )
74
+    title = models.CharField('Title', max_length=200,)
75
+    text = models.TextField('Text', blank=True, null=True,)
76
+    user = models.ForeignKey(User, blank=True, null=True, verbose_name='User')
58 77
     created = models.DateTimeField(auto_now_add=True)
59 78
     modified = models.DateTimeField(auto_now=True)
60 79
 
@@ -73,17 +92,27 @@ def attachment_path(instance, filename):
73 92
     path = 'tickets/%s' % instance.ticket.id
74 93
     print(path)
75 94
     att_path = os.path.join(settings.MEDIA_ROOT, path)
76
-    if settings.DEFAULT_FILE_STORAGE == "django.core.files.storage.FileSystemStorage":
95
+    if settings.DEFAULT_FILE_STORAGE == "django.core.files. \
96
+                                         storage.FileSystemStorage":
77 97
         if not os.path.exists(att_path):
78 98
             os.makedirs(att_path, 0777)
79 99
     return os.path.join(path, filename)
80 100
 
81 101
 
82 102
 class Attachment(models.Model):
83
-    ticket = models.ForeignKey(Ticket, verbose_name='Ticket', )
84
-    file = models.FileField('File', upload_to=attachment_path, max_length=1000, )
85
-    filename = models.CharField('Filename', max_length=1000, )
86
-    user = models.ForeignKey(User, blank=True, null=True, verbose_name='User', )
103
+    ticket = models.ForeignKey(Ticket, verbose_name='Ticket')
104
+
105
+    file = models.FileField('File',
106
+                            upload_to=attachment_path,
107
+                            max_length=1000)
108
+
109
+    filename = models.CharField('Filename', max_length=1000)
110
+
111
+    user = models.ForeignKey(User,
112
+                             blank=True,
113
+                             null=True,
114
+                             verbose_name='User')
115
+
87 116
     created = models.DateTimeField(auto_now_add=True)
88 117
 
89 118
     def get_upload_to(self, field_attname):
@@ -95,6 +124,6 @@ class Attachment(models.Model):
95 124
         )
96 125
 
97 126
     class Meta:
98
-        #ordering = ['filename', ]
127
+        # ordering = ['filename', ]
99 128
         verbose_name = 'Attachment'
100 129
         verbose_name_plural = 'Attachments'

+ 13
- 11
main/views.py View File

@@ -9,7 +9,8 @@ from django.core.mail import send_mail
9 9
 
10 10
 from .models import Ticket, Attachment, FollowUp
11 11
 from .forms import UserSettingsForm
12
-from .forms import TicketCreateForm, TicketEditForm, FollowupForm, AttachmentForm
12
+from .forms import TicketCreateForm, TicketEditForm, \
13
+                   FollowupForm, AttachmentForm
13 14
 
14 15
 # Logging
15 16
 import logging
@@ -30,13 +31,14 @@ def inbox_view(request):
30 31
 
31 32
 def my_tickets_view(request):
32 33
 
33
-    tickets = Ticket.objects.filter(assigned_to=request.user).exclude(status__exact="DONE")
34
-    tickets_waiting = Ticket.objects.filter(waiting_for=request.user).filter(status__exact="WAITING")
34
+    tickets = Ticket.objects.filter(assigned_to=request.user) \
35
+                    .exclude(status__exact="DONE")
36
+    tickets_waiting = Ticket.objects.filter(waiting_for=request.user) \
37
+                                    .filter(status__exact="WAITING")
35 38
 
36
-    
37 39
     return render_to_response('main/my-tickets.html',
38 40
                               {"tickets": tickets,
39
-                               "tickets_waiting": tickets_waiting },
41
+                               "tickets_waiting": tickets_waiting},
40 42
                               context_instance=RequestContext(request))
41 43
 
42 44
 
@@ -81,7 +83,7 @@ def usersettings_update_view(request):
81 83
     else:
82 84
         form_user = UserSettingsForm(instance=user)
83 85
 
84
-    return render(request, 'main/settings.html', {'form_user': form_user,})
86
+    return render(request, 'main/settings.html', {'form_user': form_user, })
85 87
 
86 88
 
87 89
 def ticket_create_view(request):
@@ -156,15 +158,15 @@ def followup_create_view(request):
156 158
             ticket = Ticket.objects.get(id=request.POST['ticket'])
157 159
             # mail notification to owner of ticket
158 160
             notification_subject = "[#" + str(ticket.id) + "] New followup"
159
-            notification_body = "Hi,\n\na new followup was created for ticket #" \
161
+            notification_body = "Hi,\n\n new followup created for ticket #" \
160 162
                                 + str(ticket.id) \
161 163
                                 + " (http://localhost:8000/ticket/" \
162 164
                                 + str(ticket.id) \
163 165
                                 + "/)\n\nTitle: " + form.data['title'] \
164 166
                                 + "\n\n" + form.data['text']
165 167
 
166
-            send_mail(notification_subject, notification_body, 'test@suenkler.info',
167
-                            [ticket.owner.email], fail_silently=False)
168
+            send_mail(notification_subject, notification_body, 'test@test.tld',
169
+                      [ticket.owner.email], fail_silently=False)
168 170
 
169 171
             return redirect('inbox')
170 172
 
@@ -207,8 +209,8 @@ def attachment_create_view(request):
207 209
                 file=request.FILES['file'],
208 210
                 filename=request.FILES['file'].name,
209 211
                 user=request.user
210
-                #mime_type=form.file.get_content_type(),
211
-                #size=len(form.file),
212
+                # mime_type=form.file.get_content_type(),
213
+                # size=len(form.file),
212 214
             )
213 215
             attachment.save()
214 216
 

+ 9
- 6
tickets/settings.py View File

@@ -3,6 +3,8 @@
3 3
 # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
4 4
 import os
5 5
 import socket
6
+# request.path in templates:
7
+from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS as TCP
6 8
 
7 9
 BASE_DIR = os.path.dirname(os.path.dirname(__file__))
8 10
 
@@ -32,8 +34,6 @@ INSTALLED_APPS = (
32 34
     'main',
33 35
 )
34 36
 
35
-# request.path in templates:
36
-from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS as TCP
37 37
 TEMPLATE_CONTEXT_PROCESSORS = TCP + (
38 38
     'django.core.context_processors.request',
39 39
 )
@@ -96,11 +96,13 @@ CRISPY_TEMPLATE_PACK = 'bootstrap3'
96 96
 # Define who gets code error notifications.
97 97
 # When DEBUG=False and a view raises an exception,
98 98
 # Django will email these people with the full exception information.
99
-ADMINS = ((os.environ["DJANGO_ADMIN_NAME"], os.environ["DJANGO_ADMIN_EMAIL"]), )
99
+ADMINS = ((os.environ["DJANGO_ADMIN_NAME"],
100
+           os.environ["DJANGO_ADMIN_EMAIL"]), )
100 101
 
101 102
 # Specifies who should get broken link notifications when
102 103
 # BrokenLinkEmailsMiddleware is enabled.
103
-MANAGERS = ((os.environ["DJANGO_ADMIN_NAME"], os.environ["DJANGO_ADMIN_EMAIL"]), )
104
+MANAGERS = ((os.environ["DJANGO_ADMIN_NAME"],
105
+             os.environ["DJANGO_ADMIN_EMAIL"]), )
104 106
 
105 107
 # Email delivery to local Postfix-Installation
106 108
 EMAIL_HOST = os.environ["DJANGO_EMAIL_HOST"]
@@ -113,7 +115,8 @@ LOGGING = {
113 115
     'disable_existing_loggers': False,
114 116
     'formatters': {
115 117
         'verbose': {
116
-            'format': "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
118
+            'format': "[%(asctime)s] %(levelname)s \
119
+                       [%(name)s:%(lineno)s] %(message)s",
117 120
             'datefmt': "%d/%b/%Y %H:%M:%S"
118 121
         },
119 122
         'simple': {
@@ -148,4 +151,4 @@ LOGGING = {
148 151
             'level': 'INFO',
149 152
         },
150 153
     }
151
-}
154
+}

+ 41
- 12
tickets/urls.py View File

@@ -10,37 +10,66 @@ from django.contrib.auth.decorators import login_required
10 10
 from django.conf import settings
11 11
 from django.conf.urls.static import static
12 12
 
13
-urlpatterns = patterns('',
13
+urlpatterns = patterns(
14
+    '',
14 15
 
15 16
     # Login and settings pages
16 17
     url(r'^$', 'django.contrib.auth.views.login'),
18
+
17 19
     url(r'^logout/$', 'django.contrib.auth.views.logout_then_login'),
18
-    url(r'^settings/$', login_required(main.views.usersettings_update_view), name='user-settings'),
20
+
21
+    url(r'^settings/$',
22
+        login_required(main.views.usersettings_update_view),
23
+        name='user-settings'),
19 24
 
20 25
     # Django admin
21 26
     url(r'^admin/', include(admin.site.urls)),
22 27
 
23 28
     # create new ticket
24
-    url(r'^ticket/new/$', login_required(main.views.ticket_create_view), name='ticket_new'),
29
+    url(r'^ticket/new/$',
30
+        login_required(main.views.ticket_create_view),
31
+        name='ticket_new'),
25 32
 
26 33
     # edit ticket
27
-    url(r'^ticket/edit/(?P<pk>\d+)/$', login_required(main.views.ticket_edit_view), name='ticket_edit'),
34
+    url(r'^ticket/edit/(?P<pk>\d+)/$',
35
+        login_required(main.views.ticket_edit_view),
36
+        name='ticket_edit'),
28 37
 
29 38
     # view ticket
30
-    url(r'^ticket/(?P<pk>\d+)/$', login_required(main.views.ticket_detail_view), name='ticket_detail'),
39
+    url(r'^ticket/(?P<pk>\d+)/$',
40
+        login_required(main.views.ticket_detail_view),
41
+        name='ticket_detail'),
31 42
 
32 43
     # create new followup
33
-    url(r'^followup/new/$', login_required(main.views.followup_create_view), name='followup_new'),
44
+    url(r'^followup/new/$',
45
+        login_required(main.views.followup_create_view),
46
+        name='followup_new'),
34 47
 
35 48
     # edit followup
36
-    url(r'^followup/edit/(?P<pk>\d+)/$', login_required(main.views.followup_edit_view), name='followup_edit'),
49
+    url(r'^followup/edit/(?P<pk>\d+)/$',
50
+        login_required(main.views.followup_edit_view),
51
+        name='followup_edit'),
37 52
 
38 53
     # create new attachment
39
-    url(r'^attachment/new/$', login_required(main.views.attachment_create_view), name='attachment_new'),
54
+    url(r'^attachment/new/$',
55
+        login_required(main.views.attachment_create_view),
56
+        name='attachment_new'),
40 57
 
41 58
     # ticket overviews
42
-    url(r'^inbox/$', login_required(main.views.inbox_view), name='inbox'),
43
-    url(r'^my-tickets/$', login_required(main.views.my_tickets_view), name='my-tickets'),
44
-    url(r'^all-tickets/$', login_required(main.views.all_tickets_view), name='all-tickets'),
45
-    url(r'^archive/$', login_required(main.views.archive_view), name='archive'),
59
+    url(r'^inbox/$',
60
+        login_required(main.views.inbox_view),
61
+        name='inbox'),
62
+
63
+    url(r'^my-tickets/$',
64
+        login_required(main.views.my_tickets_view),
65
+        name='my-tickets'),
66
+
67
+    url(r'^all-tickets/$',
68
+        login_required(main.views.all_tickets_view),
69
+        name='all-tickets'),
70
+
71
+    url(r'^archive/$',
72
+        login_required(main.views.archive_view),
73
+        name='archive'),
74
+
46 75
 ) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Loading…
Cancel
Save