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 7 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
 # compiled python files
1
 # compiled python files
2
 *.py[cod]
2
 *.py[cod]
3
- 
3
+
4
 # emacs temp files
4
 # emacs temp files
5
 *~
5
 *~
6
 [#]*[#]
6
 [#]*[#]
23
 
23
 
24
 # bash script to set environment variables
24
 # bash script to set environment variables
25
 env.sh
25
 env.sh
26
+
27
+# static root folder for local deployments
28
+static_root

+ 4
- 3
README.md View File

34
 export DJANGO_LOG_FILE="xxx"
34
 export DJANGO_LOG_FILE="xxx"
35
 
35
 
36
 # static and media files dir in production
36
 # static and media files dir in production
37
-export DJANGO_STATIC_ROOT="xxx"
37
+export DJANGO_STATIC_ROOT="static_root/"
38
 export DJANGO_MEDIA_ROOT="xxx"
38
 export DJANGO_MEDIA_ROOT="xxx"
39
 
39
 
40
 # User who gets django's email notifications (ADMINS/MANAGERS), see settings.py
40
 # User who gets django's email notifications (ADMINS/MANAGERS), see settings.py
56
 export DJANGO_TICKET_EMAIL_NOTIFICATIONS_TO="xxx"
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
 $ git clone https://github.com/suenkler/django-tickets.git
62
 $ git clone https://github.com/suenkler/django-tickets.git
64
 $ pip install -r requirements.txt
64
 $ pip install -r requirements.txt
65
 $ source env.sh
65
 $ source env.sh
66
 $ ./manage.py migrate
66
 $ ./manage.py migrate
67
+$ ./manage.py collectstatic
67
 $ ./manage.py createsuperuser
68
 $ ./manage.py createsuperuser
68
 $ ./manage.py runserver
69
 $ ./manage.py runserver
69
 ```
70
 ```
72
 
73
 
73
 ```
74
 ```
74
 $ ./manage.py get_email
75
 $ ./manage.py get_email
75
-```
76
+```

+ 3
- 2
main/forms.py View File

18
         model = Ticket
18
         model = Ticket
19
         fields = ('title', 'description')
19
         fields = ('title', 'description')
20
 
20
 
21
-        
21
+
22
 class TicketEditForm(forms.ModelForm):
22
 class TicketEditForm(forms.ModelForm):
23
     class Meta:
23
     class Meta:
24
         model = Ticket
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
 class FollowupForm(forms.ModelForm):
29
 class FollowupForm(forms.ModelForm):

+ 45
- 16
main/models.py View File

13
     """
13
     """
14
     return 'last_name, first_name' for User by default
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
 User.__unicode__ = user_unicode
19
 User.__unicode__ = user_unicode
18
 
20
 
19
 
21
 
20
 class Ticket(models.Model):
22
 class Ticket(models.Model):
21
 
23
 
22
     title = models.CharField('Title', max_length=255)
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
     description = models.TextField('Description', blank=True, null=True)
32
     description = models.TextField('Description', blank=True, null=True)
25
 
33
 
26
     STATUS_CHOICES = (
34
     STATUS_CHOICES = (
29
         ('WAITING', 'WAITING'),
37
         ('WAITING', 'WAITING'),
30
         ('DONE', 'DONE'),
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
     assigned_to = models.ForeignKey(User,
55
     assigned_to = models.ForeignKey(User,
37
                                     related_name='assigned_to',
56
                                     related_name='assigned_to',
38
                                     blank=True,
57
                                     blank=True,
39
                                     null=True,
58
                                     null=True,
40
-                                    verbose_name='Assigned to',)
59
+                                    verbose_name='Assigned to')
41
 
60
 
42
     created = models.DateTimeField(auto_now_add=True)
61
     created = models.DateTimeField(auto_now_add=True)
43
     updated = models.DateTimeField(auto_now=True)
62
     updated = models.DateTimeField(auto_now=True)
50
     """
69
     """
51
     A FollowUp is a comment to a ticket.
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
     date = models.DateTimeField('Date', default=timezone.now)
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
     created = models.DateTimeField(auto_now_add=True)
77
     created = models.DateTimeField(auto_now_add=True)
59
     modified = models.DateTimeField(auto_now=True)
78
     modified = models.DateTimeField(auto_now=True)
60
 
79
 
73
     path = 'tickets/%s' % instance.ticket.id
92
     path = 'tickets/%s' % instance.ticket.id
74
     print(path)
93
     print(path)
75
     att_path = os.path.join(settings.MEDIA_ROOT, path)
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
         if not os.path.exists(att_path):
97
         if not os.path.exists(att_path):
78
             os.makedirs(att_path, 0777)
98
             os.makedirs(att_path, 0777)
79
     return os.path.join(path, filename)
99
     return os.path.join(path, filename)
80
 
100
 
81
 
101
 
82
 class Attachment(models.Model):
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
     created = models.DateTimeField(auto_now_add=True)
116
     created = models.DateTimeField(auto_now_add=True)
88
 
117
 
89
     def get_upload_to(self, field_attname):
118
     def get_upload_to(self, field_attname):
95
         )
124
         )
96
 
125
 
97
     class Meta:
126
     class Meta:
98
-        #ordering = ['filename', ]
127
+        # ordering = ['filename', ]
99
         verbose_name = 'Attachment'
128
         verbose_name = 'Attachment'
100
         verbose_name_plural = 'Attachments'
129
         verbose_name_plural = 'Attachments'

+ 13
- 11
main/views.py View File

9
 
9
 
10
 from .models import Ticket, Attachment, FollowUp
10
 from .models import Ticket, Attachment, FollowUp
11
 from .forms import UserSettingsForm
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
 # Logging
15
 # Logging
15
 import logging
16
 import logging
30
 
31
 
31
 def my_tickets_view(request):
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
     return render_to_response('main/my-tickets.html',
39
     return render_to_response('main/my-tickets.html',
38
                               {"tickets": tickets,
40
                               {"tickets": tickets,
39
-                               "tickets_waiting": tickets_waiting },
41
+                               "tickets_waiting": tickets_waiting},
40
                               context_instance=RequestContext(request))
42
                               context_instance=RequestContext(request))
41
 
43
 
42
 
44
 
81
     else:
83
     else:
82
         form_user = UserSettingsForm(instance=user)
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
 def ticket_create_view(request):
89
 def ticket_create_view(request):
156
             ticket = Ticket.objects.get(id=request.POST['ticket'])
158
             ticket = Ticket.objects.get(id=request.POST['ticket'])
157
             # mail notification to owner of ticket
159
             # mail notification to owner of ticket
158
             notification_subject = "[#" + str(ticket.id) + "] New followup"
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
                                 + str(ticket.id) \
162
                                 + str(ticket.id) \
161
                                 + " (http://localhost:8000/ticket/" \
163
                                 + " (http://localhost:8000/ticket/" \
162
                                 + str(ticket.id) \
164
                                 + str(ticket.id) \
163
                                 + "/)\n\nTitle: " + form.data['title'] \
165
                                 + "/)\n\nTitle: " + form.data['title'] \
164
                                 + "\n\n" + form.data['text']
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
             return redirect('inbox')
171
             return redirect('inbox')
170
 
172
 
207
                 file=request.FILES['file'],
209
                 file=request.FILES['file'],
208
                 filename=request.FILES['file'].name,
210
                 filename=request.FILES['file'].name,
209
                 user=request.user
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
             attachment.save()
215
             attachment.save()
214
 
216
 

+ 9
- 6
tickets/settings.py View File

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

+ 41
- 12
tickets/urls.py View File

10
 from django.conf import settings
10
 from django.conf import settings
11
 from django.conf.urls.static import static
11
 from django.conf.urls.static import static
12
 
12
 
13
-urlpatterns = patterns('',
13
+urlpatterns = patterns(
14
+    '',
14
 
15
 
15
     # Login and settings pages
16
     # Login and settings pages
16
     url(r'^$', 'django.contrib.auth.views.login'),
17
     url(r'^$', 'django.contrib.auth.views.login'),
18
+
17
     url(r'^logout/$', 'django.contrib.auth.views.logout_then_login'),
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
     # Django admin
25
     # Django admin
21
     url(r'^admin/', include(admin.site.urls)),
26
     url(r'^admin/', include(admin.site.urls)),
22
 
27
 
23
     # create new ticket
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
     # edit ticket
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
     # view ticket
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
     # create new followup
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
     # edit followup
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
     # create new attachment
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
     # ticket overviews
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
 ) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
75
 ) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Loading…
Cancel
Save