Add buses link to adm-index
- Author
- Maarten Vangeneugden
- Date
- Aug. 24, 2018, 12:22 a.m.
- Hash
- 75a3cedc225b0d39f080c4fa7dca9051b974788a
- Parent
- 30d7e2a1ac283b2789d938f219e1ff66905fcdb9
- Modified files
- administration/templates/administration/buses.djhtml
- administration/urls.py
- administration/views.py
- docs/thesis/aandachtspunten.org
- docs/thesis/client-side-scripting.org
- docs/thesis/toekomst.org
administration/templates/administration/buses.djhtml ¶
2 additions and 1 deletion.
View changes Hide changes
1 |
1 |
{% load i18n %} |
2 |
2 |
{% load humanize %} |
3 |
3 |
{% load joeni_org %} |
4 |
4 |
|
5 |
5 |
{% block title %} |
6 |
6 |
{% trans "Buses" %} | {{ block.super }} |
7 |
7 |
{% endblock %} |
8 |
8 |
|
9 |
9 |
{% block main %} |
10 |
10 |
<h1>{% trans "Bus departures" %}</h1> |
11 |
11 |
<h2 id="diepenbeek">Campus Diepenbeek</h2> |
12 |
12 |
<div class="flex-container"> |
13 |
13 |
{% for bus in departures_diepenbeek %} |
14 |
14 |
<div class="flex-items timetable" style="border-color: {{ bus.color }};"> |
15 |
15 |
<span class="number" style="background-color: {{ bus.color }};"> |
16 |
16 |
{{ bus.number }}</span> |
17 |
17 |
{{ bus.time|time }} |
18 |
18 |
<span style="color: {{ bus.color }}; font-weight:bold;">🡺</span> |
19 |
19 |
{{ bus.destination }} |
20 |
20 |
<div class="timetable-under"> |
21 |
21 |
<time>{{ bus.time|naturaltime|capfirst }}</time> |
22 |
22 |
{% if bus.via %} |
23 |
23 |
<span class="undernote">| Gaat via {{ bus.via }}</span> |
24 |
- | {% endif %} |
+ |
24 |
<span class="undernote"> Gaat via {{ bus.via }}</span> |
+ |
25 |
{% endif %} |
25 |
26 |
</div> |
26 |
27 |
</div> |
27 |
28 |
{% empty %} |
28 |
29 |
{% trans "There are currently no buses that stop here." %} |
29 |
30 |
{% endfor %} |
30 |
31 |
</div> |
31 |
32 |
|
32 |
33 |
<h2 id="hasselt">Campus Hasselt (Dusartplein)</h2> |
33 |
34 |
<div class="flex-container"> |
34 |
35 |
{% for bus in departures_dusart %} |
35 |
36 |
<div class="flex-items timetable" style="border-color: {{ bus.color }};"> |
36 |
37 |
<span class="number" style="background-color: {{ bus.color }};"> |
37 |
38 |
{{ bus.number }}</span> |
38 |
39 |
{{ bus.time|time }} |
39 |
40 |
<span style="color: {{ bus.color }}; font-weight:bold;">🡺</span> |
40 |
41 |
{{ bus.destination }} |
41 |
42 |
<div class="timetable-under"> |
42 |
43 |
<time>{{ bus.time|naturaltime|capfirst }}</time> |
43 |
44 |
{% if bus.via %} |
44 |
45 |
<span style="color: {{ bus.color }}; font-weight:bold;">|</span> |
45 |
46 |
<span class="undernote"> Gaat via {{ bus.via }}</span> |
46 |
47 |
{% endif %} |
47 |
48 |
</div> |
48 |
49 |
</div> |
49 |
50 |
{% empty %} |
50 |
51 |
{% trans "There are currently no buses that stop here." %} |
51 |
52 |
{% endfor %} |
52 |
53 |
</div> |
53 |
54 |
|
54 |
55 |
|
55 |
56 |
{% endblock main %} |
56 |
57 |
administration/urls.py ¶
0 additions and 4 deletions.
View changes Hide changes
1 |
1 |
from django.contrib.auth import views as auth_views |
2 |
2 |
from . import views |
3 |
3 |
from django.utils.translation import gettext_lazy as _ |
4 |
4 |
|
5 |
5 |
urlpatterns = ([ |
6 |
6 |
path('', views.index, name='administration-index'), |
7 |
7 |
path(_('pre-registration'), views.pre_registration, name='administration-pre-registration'), # HOLD |
8 |
8 |
path(_('settings'), views.settings, name='administration-settings'), |
9 |
9 |
path(_('curriculum'), views.curriculum, name='administration-curriculum'), # TODO |
10 |
10 |
# Commented because they might very well be merged with curriculum |
11 |
- | #path(_('results'), views.results, name='administration-results'), |
12 |
- | #path(_('results/<slug:course>'), views.result, name='administration-results'), |
13 |
- | #path(_('results/<int:student_id>'), views.result, name='administration-results'), |
14 |
- | path(_('forms'), views.forms, name='administration-forms'), # In Dutch: "Attesten" # HOLD |
15 |
11 |
path(_('forms/<str:form>'), views.forms, name='administration-forms'), # HOLD |
16 |
12 |
path(_('rooms'), views.rooms, name='administration-rooms'), # TODO |
17 |
13 |
path(_('rooms/<str:room>'), views.room_detail, name='administration-room-detail'), # TODO |
18 |
14 |
#path(_('rooms/reservate'), views.room_reservate, name='administration-room-reservate'), |
19 |
15 |
path(_('roster'), views.roster, name='administration-roster'), # TODO |
20 |
16 |
re_path(_('roster/(?P<begin>[0-9]{2}-[0-9]{2}-[0-9]{4})/(?P<end>[0-9]{2}-[0-9]{2}-[0-9]{4})'), views.roster, name='administration-roster'), # TODO |
21 |
17 |
path(_('jobs'), views.jobs, name='administration-jobs'), # HOLD |
22 |
18 |
path(_('bulletin-board'), views.bulletin_board, name='administration-bulletin-board'), # TODO |
23 |
19 |
path(_('user/<slug:slug_name>'), views.user, name='administration-user'), # TODO |
24 |
20 |
path(_('buses'), views.buses, name='administration-buses'), |
25 |
21 |
path(_('roster/<slug:user_slug>.ics'), views.roster_ics, name='administration-roster-ics'), # TODO |
26 |
22 |
|
27 |
23 |
path('login', views.login, name='administration-login'), # FIXME |
28 |
24 |
]) |
29 |
25 |
administration/views.py ¶
4 additions and 0 deletions.
View changes Hide changes
1 |
1 |
from . import bus |
2 |
2 |
from collections import OrderedDict |
3 |
3 |
from django.http import HttpResponseRedirect |
4 |
4 |
import datetime |
5 |
5 |
from django.urls import reverse # Why? |
6 |
6 |
from django.utils.translation import gettext as _ |
7 |
7 |
from .models import * |
8 |
8 |
from .forms import UserDataForm |
9 |
9 |
from .new_roster import create_roster_rows |
10 |
10 |
import administration |
11 |
11 |
from django.contrib.auth.decorators import login_required |
12 |
12 |
from django.contrib.auth import authenticate |
13 |
13 |
from django.contrib.auth import login as login_auth |
14 |
14 |
|
15 |
15 |
@login_required |
16 |
16 |
def roster(request, begin=None, end=None): |
17 |
17 |
"""Collects and renders the data that has to be displayed in the roster. |
18 |
18 |
|
19 |
19 |
The begin and end date can be specified. Only roster points in that range |
20 |
20 |
will be included in the response. If no begin and end are specified, it will |
21 |
21 |
take the current week as begin and end point. If it's |
22 |
22 |
weekend, it will take next week.""" |
23 |
23 |
|
24 |
24 |
# TODO Handle given begin and end |
25 |
25 |
context = dict() |
26 |
26 |
#context = {'money' : update_balance(None)} |
27 |
27 |
template = "administration/roster.djhtml" |
28 |
28 |
|
29 |
29 |
if begin is None or end is None: |
30 |
30 |
today = datetime.date.today() |
31 |
31 |
if today.isoweekday() in {6,7}: # Weekend |
32 |
32 |
begin = today + datetime.timedelta(days=8-today.isoweekday()) |
33 |
33 |
end = today + datetime.timedelta(days=13-today.isoweekday()) |
34 |
34 |
else: # Same week |
35 |
35 |
begin = today - datetime.timedelta(days=today.weekday()) |
36 |
36 |
end = today + datetime.timedelta(days=5-today.isoweekday()) |
37 |
37 |
else: # Changing regexes to date objects |
38 |
38 |
b = begin.split("-") |
39 |
39 |
e = end.split("-") |
40 |
40 |
begin = datetime.datetime(int(b[2]),int(b[1]),int(b[0])) |
41 |
41 |
end = datetime.datetime(int(e[2]),int(e[1]),int(e[0])) |
42 |
42 |
|
43 |
43 |
context['begin'] = begin |
44 |
44 |
context['end'] = end |
45 |
45 |
|
46 |
46 |
context['prev_begin'] = (begin - datetime.timedelta(days=7)).strftime("%d-%m-%Y") |
47 |
47 |
context['prev_end'] = (begin - datetime.timedelta(days=2)).strftime("%d-%m-%Y") |
48 |
48 |
context['next_begin'] = (end + datetime.timedelta(days=2)).strftime("%d-%m-%Y") |
49 |
49 |
context['next_end'] = (end + datetime.timedelta(days=7)).strftime("%d-%m-%Y") |
50 |
50 |
|
51 |
51 |
days = [begin] |
52 |
52 |
while (end-days[-1]).days != 0: |
53 |
53 |
# Human translation: Keep adding days until the last day in the array of |
54 |
54 |
# days is the same day as the last day the user wants to see the roster for. |
55 |
55 |
days.append(days[-1] + datetime.timedelta(days=1)) |
56 |
56 |
context['days'] = days |
57 |
57 |
|
58 |
58 |
# Collecting events |
59 |
59 |
course_events = CourseEvent.objects.filter(begin_time__gte=begin).filter(end_time__lte=end).order_by("begin_time") |
60 |
60 |
#university_events = UniversityEvent.objects.filter(begin_time__gte=begin).filter(end_time__lte=end) |
61 |
61 |
#study_events = StudyEvent.objects.filter(begin_time__gte=begin).filter(end_time__lte=end) |
62 |
62 |
#events = Event.objects.filter(begin_time__gte=begin).filter(end_time__lte=end) |
63 |
63 |
conflicts, table_code = create_roster_rows(course_events) |
64 |
64 |
|
65 |
65 |
context['time_blocks'] = table_code |
66 |
66 |
context['conflicts'] = conflicts |
67 |
67 |
#print(time_blocks) |
68 |
68 |
return render(request, template, context) |
69 |
69 |
# TODO Finish! |
70 |
70 |
|
71 |
71 |
def roster_ics(request, user_slug): |
72 |
72 |
template = "administration/roster.ics" |
73 |
73 |
context = dict() |
74 |
74 |
context['events'] = CourseEvent.objects.all() # FIXME: Filter to personal calendar items! |
75 |
75 |
return render(request, template, context) |
76 |
76 |
|
77 |
77 |
def index(request): |
78 |
78 |
template = "administration/index.djhtml" |
79 |
79 |
#context = {'money': update_balance(None)} |
80 |
80 |
context = dict() |
81 |
81 |
context['links'] = [ |
82 |
82 |
("administration-settings", |
83 |
83 |
_("Personal settings"), |
84 |
84 |
_("Edit your personal information, billing address, home address, and so on.")), |
85 |
85 |
("administration-curriculum", |
86 |
86 |
_("Curricula"), |
87 |
87 |
_("View all information related to your curricula, including exam results.<br />" |
88 |
88 |
"You can also change your current curriculum here, or request a change.")), |
89 |
89 |
("administration-forms", |
+ |
90 |
_("Bus departures"), |
+ |
91 |
_("If you're leaving Hasselt University, you can check the bus departures from " |
+ |
92 |
"your campus here.")), |
+ |
93 |
("administration-forms", |
90 |
94 |
_("Forms"), |
91 |
95 |
_("All forms for special services can be found on this page.")), |
92 |
96 |
("administration-rooms", |
93 |
97 |
_("Rooms"), |
94 |
98 |
_("Room occupancy, free rooms, properties, ... <br />" |
95 |
99 |
"All this and much more is available on this page.")), |
96 |
100 |
("administration-roster", |
97 |
101 |
_("Personal roster"), |
98 |
102 |
_("Everything about your roster and events at Hasselt University is available here.")), |
99 |
103 |
("administration-bulletin-board", |
100 |
104 |
_("Bulletin board"), |
101 |
105 |
_("From time to time, UHasselt publishes announcements regarding changes, events, ..." |
102 |
106 |
"<br />All publications are neatly organized here for easy reference.")), |
103 |
107 |
] |
104 |
108 |
|
105 |
109 |
return render(request, template, context) |
106 |
110 |
|
107 |
111 |
pass |
108 |
112 |
|
109 |
113 |
def pre_registration(request): |
110 |
114 |
user_data_form = UserDataForm() |
111 |
115 |
template = "administration/pre_registration.djhtml" |
112 |
116 |
context = dict() |
113 |
117 |
|
114 |
118 |
if request.method == 'POST': |
115 |
119 |
user_data_form = UserDataForm(request.POST) |
116 |
120 |
context['user_data_form'] = user_data_form |
117 |
121 |
if user_data_form.is_valid(): |
118 |
122 |
user_data_form.save() |
119 |
123 |
context['messsage'] = _("Your registration has been completed. You will receive an e-mail shortly.") |
120 |
124 |
else: |
121 |
125 |
context['messsage'] = _("The data you supplied had errors. Please review your submission.") |
122 |
126 |
else: |
123 |
127 |
context['user_data_form'] = UserDataForm(instance = user_data_form) |
124 |
128 |
|
125 |
129 |
return render(request, template, context) |
126 |
130 |
pass |
127 |
131 |
|
128 |
132 |
@login_required |
129 |
133 |
def settings(request): |
130 |
134 |
user_data = UserData.objects.get(user=request.user) |
131 |
135 |
user_data_form = UserDataForm(instance = user_data) |
132 |
136 |
template = "administration/settings.djhtml" |
133 |
137 |
context = dict() |
134 |
138 |
#context = {'money' : update_balance(None)} |
135 |
139 |
|
136 |
140 |
if request.method == 'POST': |
137 |
141 |
user_data_form = UserDataForm(request.POST, instance = user_data) |
138 |
142 |
context['user_data_form'] = user_data_form |
139 |
143 |
if user_data_form.is_valid(): |
140 |
144 |
user_data_form.save() |
141 |
145 |
context['messsage'] = _("Your settings were successfully updated.") |
142 |
146 |
else: |
143 |
147 |
context['messsage'] = _("The data you supplied had errors. Please review your submission.") |
144 |
148 |
else: |
145 |
149 |
context['user_data_form'] = UserDataForm(instance = user_data) |
146 |
150 |
|
147 |
151 |
return render(request, template, context) |
148 |
152 |
|
149 |
153 |
@login_required |
150 |
154 |
def bulletin_board(request): |
151 |
155 |
context = dict() |
152 |
156 |
#context = {'money' : update_balance(None)} |
153 |
157 |
context['exam_commission_decisions'] = ExamCommissionDecision.objects.filter(user=request.user) |
154 |
158 |
context['education_department_messages'] = EducationDepartmentMessages.objects.all() |
155 |
159 |
for item in context['education_department_messages']: |
156 |
160 |
print(item.text) |
157 |
161 |
template = "administration/bulletin_board.djhtml" |
158 |
162 |
return render(request, template, context) |
159 |
163 |
|
160 |
164 |
def jobs(request): |
161 |
165 |
context = dict() |
162 |
166 |
#context = {'money' : update_balance(None)} |
163 |
167 |
template = "administration/jobs.djhtml" |
164 |
168 |
#@context['decisions'] = ExamCommissionDecision.objects.filter(user=request.user) |
165 |
169 |
return render(request, template, context) |
166 |
170 |
|
167 |
171 |
|
168 |
172 |
@login_required |
169 |
173 |
def curriculum(request): |
170 |
174 |
context = dict() |
171 |
175 |
#context = {'money' : update_balance(None)} |
172 |
176 |
template = "administration/curriculum.djhtml" |
173 |
177 |
context['curricula'] = Curriculum.objects.filter(student=request.user) |
174 |
178 |
for item in context['curricula']: |
175 |
179 |
for co in item.course_programmes_results(): |
176 |
180 |
print(co) |
177 |
181 |
return render(request, template, context) |
178 |
182 |
|
179 |
183 |
def result(request): |
180 |
184 |
return render(request, template, context) |
181 |
185 |
|
182 |
186 |
@login_required |
183 |
187 |
def results(request): |
184 |
188 |
results = CourseResult.objects.filter(student=request.user) |
185 |
189 |
template = "administration/results.djhtml" |
186 |
190 |
# TODO |
187 |
191 |
return render(request, template, context) |
188 |
192 |
|
189 |
193 |
def forms(request): |
190 |
194 |
context = dict() |
191 |
195 |
#context = {'money' : update_balance(None)} |
192 |
196 |
template = "administration/forms.djhtml" |
193 |
197 |
return render(request, template, context) |
194 |
198 |
|
195 |
199 |
def user(request, slug_name): |
196 |
200 |
pass |
197 |
201 |
|
198 |
202 |
def rooms(request): |
199 |
203 |
context = dict() |
200 |
204 |
#context = {'money' : update_balance(None)} |
201 |
205 |
context['rooms'] = Room.objects.all() |
202 |
206 |
context['room_reservations'] = RoomReservation.objects.all() |
203 |
207 |
context['course_events'] = CourseEvent.objects.all() |
204 |
208 |
context['blocks'] = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] |
205 |
209 |
|
206 |
210 |
# Collecting all rooms that are free for at least one two hours from now |
207 |
211 |
now = datetime.datetime.now(datetime.timezone.utc) |
208 |
212 |
end = now + datetime.timedelta(hours=2) |
209 |
213 |
free_rooms = dict() |
210 |
214 |
for room in context['rooms']: |
211 |
215 |
if room.reservation_possible(now, end): |
212 |
216 |
event = room.next_event(end) |
213 |
217 |
reservation = room.next_reservation(end) |
214 |
218 |
if event is None and reservation is None: |
215 |
219 |
free_rooms[room] = None |
216 |
220 |
elif reservation is not None: |
217 |
221 |
free_rooms[room] = event.begin_time |
218 |
222 |
elif event is not None: |
219 |
223 |
free_rooms[room] = reservation.begin_time |
220 |
224 |
elif event.begin_time < reservation.begin_time: |
221 |
225 |
free_rooms[room] = event.begin_time |
222 |
226 |
else: |
223 |
227 |
free_rooms[room] = reservation.begin_time |
224 |
228 |
context['free_rooms'] = free_rooms |
225 |
229 |
|
226 |
230 |
template = "administration/rooms.djhtml" |
227 |
231 |
return render(request, template, context) |
228 |
232 |
|
229 |
233 |
def room_detail(request, room): |
230 |
234 |
template = "administration/room_detail.djhtml" |
231 |
235 |
context = dict() |
232 |
236 |
#context = {'money' : update_balance(None)} |
233 |
237 |
room = Room.objects.get(name=room) |
234 |
238 |
context['room'] = room |
235 |
239 |
context['reservations'] = RoomReservation.objects.filter(room=room).filter(begin_time__gte=datetime.datetime.now()) |
236 |
240 |
context['course_events'] = CourseEvent.objects.filter(room=room).filter(begin_time__gte=datetime.datetime.now()) |
237 |
241 |
# Building the room occupancy of today: |
238 |
242 |
today = datetime.date.today() |
239 |
243 |
if today.isoweekday() in {6,7}: # Weekend |
240 |
244 |
today = today + datetime.timedelta(days=8-today.isoweekday()) |
241 |
245 |
|
242 |
246 |
context['days'] = [today] |
243 |
247 |
|
244 |
248 |
# Collecting events |
245 |
249 |
course_events = CourseEvent.objects.filter(room=room).filter(begin_time__date=today) |
246 |
250 |
print(course_events) |
247 |
251 |
#university_events = UniversityEvent.objects.filter(begin_time__gte=begin).filter(end_time__lte=end) |
248 |
252 |
#study_events = StudyEvent.objects.filter(begin_time__gte=begin).filter(end_time__lte=end) |
249 |
253 |
#events = Event.objects.filter(begin_time__gte=begin).filter(end_time__lte=end) |
250 |
254 |
|
251 |
255 |
conflicts, table_code = create_roster_rows(course_events) |
252 |
256 |
context['time_blocks'] = table_code |
253 |
257 |
context['conflicts'] = conflicts |
254 |
258 |
print(context['time_blocks']) |
255 |
259 |
return render(request, template, context) |
256 |
260 |
|
257 |
261 |
def buses(request): |
258 |
262 |
context = dict() |
259 |
263 |
context["departures_diepenbeek"] = bus.arrivals(["401474","401475"]) |
260 |
264 |
#for testing: context["departures_diepenbeek"] = bus.arrivals(["205919","205916","205915"]) |
261 |
265 |
context["departures_dusart"] = bus.arrivals(["403041","403040"]) |
262 |
266 |
template = 'administration/buses.djhtml' |
263 |
267 |
return render(request, template, context) |
264 |
268 |
|
265 |
269 |
|
266 |
270 |
|
267 |
271 |
|
268 |
272 |
def login(request): |
269 |
273 |
context = dict() |
270 |
274 |
#context = {'money' : update_balance(None)} |
271 |
275 |
if request.method == "POST": |
272 |
276 |
name = request.POST['name'] |
273 |
277 |
passphrase = request.POST['pass'] |
274 |
278 |
user = authenticate(username=name, password=passphrase) |
275 |
279 |
if user is not None: # The user was successfully authenticated |
276 |
280 |
print("YA") |
277 |
281 |
login_auth(request, user) |
278 |
282 |
return HttpResponseRedirect(request.POST['next']) |
279 |
283 |
else: # User credentials were wrong |
280 |
284 |
context['next'] = request.POST['next'] |
281 |
285 |
context['message'] = _("The given credentials were not correct.") |
282 |
286 |
else: |
283 |
287 |
context['next'] = request.GET.get('next', None) |
284 |
288 |
if context['next'] is None: |
285 |
289 |
context['next'] = reverse('administration-index') |
286 |
290 |
|
287 |
291 |
template = 'administration/login.djhtml' |
288 |
292 |
|
289 |
293 |
return render(request, template, context) |
290 |
294 |
docs/thesis/aandachtspunten.org ¶
15 additions and 20 deletions.
View changes Hide changes
1 |
- | Fundamenteel is deze bachelorproef nog altijd een werk dat moet bijdragen aan |
2 |
- | het ALIPA-project van de UHasselt.\\ |
3 |
- | Voor het stroomlijnen van de ICT-infrastructuur is het ook nodig om kleine |
4 |
- | problemen en mankementen op te lossen als ze gevonden worden. Een afgewerkt |
5 |
- | geheel voedt het gevoel dat alles goed en orderlijk samenwerkt met elkaar, een |
6 |
- | belangrijke doelstelling om vertrouwen te creëren in de gebruikers. |
7 |
- | |
+ |
1 |
Fundamenteel is deze bachelorproef nog altijd een werk dat moet bijdragen aan |
+ |
2 |
het ALIPA-project van de UHasselt.\\ |
+ |
3 |
Voor het stroomlijnen van de ICT-infrastructuur is het ook nodig om kleine |
+ |
4 |
problemen en mankementen op te lossen als ze gevonden worden. Een afgewerkt |
+ |
5 |
geheel voedt het gevoel dat alles goed en orderlijk samenwerkt met elkaar, een |
+ |
6 |
belangrijke doelstelling om vertrouwen te creëren in de gebruikers. |
+ |
7 |
|
8 |
8 |
Tijdens het maken van dit proefwerk ben ik op enkele kleine punten gestoten die |
9 |
- | niet direct van invloed waren op mijn proef, maar die ik hier toch wens te |
10 |
- | vermelden. Het gaat dan om kleine slordigheden, schoonheidsfoutjes, verouderde |
11 |
- | informatie, ... |
12 |
- | |
+ |
9 |
niet direct van invloed waren op mijn proef, maar die ik hier toch wens te |
+ |
10 |
vermelden. Het gaat dan om kleine slordigheden, schoonheidsfoutjes, verouderde |
+ |
11 |
informatie, ... |
+ |
12 |
|
13 |
13 |
Alle benodigde informatie, alsook een redenering wordt per punt uitgeschreven. |
14 |
- | |
+ |
14 |
|
15 |
15 |
** Verouderde informatie |
16 |
- | *** Campushopper afgeschaft |
17 |
16 |
Op de pagina https://www.uhasselt.be/Contact-en-ligging onder de rubriek "Campus |
18 |
17 |
Hasselt/Gevangenis" wordt verteld dat men de |
19 |
18 |
Campushopper kan nemen, maar deze werd al in 2017 afgeschaft. Beter is om Boulevardpendel |
20 |
19 |
te nemen, of elke bus die het Dusartplein aandoet.[fn::Dit zijn de volgende |
21 |
20 |
lijnen: 1, 3, 5, 11, 13, 16, 18a, 20a, 22, 23, 35, 36, 45, 46, 48, 51, 52, 180, |
22 |
21 |
182, AL, BP, H13, H14, H41, H51. (https://www.delijn.be/nl/haltes/halte/403040/Hasselt_Dusartplein)] |
23 |
22 |
|
24 |
23 |
** Onnodige informatie |
25 |
- | *** Spartacusplan |
26 |
24 |
Op https://www.uhasselt.be/Contact-en-ligging staat een link naar een |
27 |
25 |
PDF-bestand omtrent het Spartacusplan. Dit heeft inderdaad te maken met het |
28 |
26 |
openbaar vervoer, maar voegt weinig toe aan het eigenlijke doel van deze pagina: |
29 |
27 |
Bezoekers informeren over hoe ze de UHasselt kunnen bereiken.\\ |
30 |
28 |
Ik stel voor om de vermelding hierover de verwijderen. |
31 |
29 |
|
32 |
30 |
*** Wachtwoorden plaintext |
33 |
31 |
*Op het Studentendossier is het eerste wachtwoord dat studenten toegewezen |
34 |
32 |
krijgen /plain text/ in te kijken.* Dit gaat via de link "Initieel paswoord". |
35 |
33 |
Het spreekt voor zich dat de implicaties voor veiligheid dicteren dat |
36 |
34 |
*het onversleuteld opslaan van wachtwoorden per direct moet stoppen.* |
37 |
35 |
** Slecht te vinden informatie |
38 |
- | *** Plattegronden |
39 |
36 |
Er is weinig te vinden van plattegronden op de website; waar zijn welke lokalen |
40 |
37 |
te vinden, plattegronden van de 1ste verdieping, ... |
41 |
38 |
|
42 |
39 |
Het kan ook zijn dat dit niet per sé nodig is; indien op de campus zelf adequate |
43 |
40 |
wegbewijzering wordt aangebracht, wordt een plattegrond minder belangrijk. |
44 |
41 |
Waar vind ik alle plattegronden van de campussen? Het zijn er maar 2... |
45 |
42 |
Ik heb er eentje gevonden van de campus Diepenbeek op https://www.uhasselt.be/Contact-en-ligging: |
46 |
43 |
https://www.uhasselt.be/images/UHasselt/maps/2015/campus-diepenbeek/campus-diepenbeek-gebouwDE.jpg |
47 |
44 |
Maar dat is ook enkel gelijkvloers, en niet up-to-date met nieuwe aanbouw. |
48 |
45 |
|
49 |
46 |
** Mogelijke versimpelingen |
50 |
- | *** Speciale logo's voor Apple |
51 |
47 |
In de broncode van de websites binnen de UHasselt zijn in de header links te |
52 |
48 |
vinden naar speciale logo's voor Apple-browsers.\\ |
53 |
49 |
Binnen Joeni worden er geen <GO ON> |
54 |
- | ** Verbeteringspunten |
55 |
- | *** Video's op YouTube |
+ |
50 |
browser. Ze voegen sowieso niet veel toe aan de eigenlijke werking van de |
+ |
51 |
website, en maken het geheel weer een beetje complexer. |
+ |
52 |
*** Video's op YouTube |
56 |
53 |
Op https://www.uhasselt.be/Videos zijn er veel filmpjes te vinden over het |
57 |
54 |
reilen en zeilen in de universiteit. Maar eigenlijk zijn het links naar het |
58 |
55 |
videoplatform YouTube, onderdeel van Google Inc. Eerder werd in deze thesis |
59 |
56 |
[[Google-privacy][de integratie met diensten van Google] op de korrel genomen.\\ |
60 |
57 |
Dit is makkelijk op te lossen door de video's simpelweg via de eigen website aan |
61 |
58 |
te bieden, middels het [[https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Video][~<video>~]]-element. |
62 |
59 |
**** Licensiëring video's |
63 |
60 |
De aangegeven licentie van de video's is de "Standaard YouTube-licentie", deze |
64 |
61 |
licentie voldoet niet aan de vereisten voor een "Vrij cultureel werk". |
65 |
62 |
|
66 |
63 |
De aard van deze video's is duidelijk: Ze dienen om toekomstige studenten te |
67 |
64 |
informeren over de UHasselt en al haar richtingen, een blik te werpen op |
68 |
65 |
studentenfaciliteiten (zoals verenigingen), en ook als een advertentie om voor |
69 |
66 |
UHasselt te kiezen.\\ |
70 |
67 |
De doelstelling bereiken wordt met deze licentiekeuze actief tegengewerkt; |
71 |
68 |
mensen mogen deze video's niet delen, of aanpassen voor nieuwe werken. Er zijn |
72 |
69 |
ook voorwaarden op het privégebruik ervan.\\ |
73 |
70 |
Creatieve werken met deze doelstellingen dienen zo vrij mogelijk uitgegeven te |
74 |
71 |
worden om de zichtbaarheid en verspreidingskansen ervan te maximaliseren. Door de huidige wetgeving |
75 |
72 |
omtrent kopieerrechten is dit niet automatisch mogelijk, maar er bestaan wel |
76 |
73 |
licenties die hiervoor een zeer toereikend soelaas bieden. |
77 |
74 |
|
78 |
75 |
Ik raad aan om de licenties op de video's te vervangen met de |
79 |
76 |
[[https://creativecommons.org/licenses/by/4.0/deed.nl][CC-BY 4.0]]-licentie, die deze problemen direct oplost. Dit kan ook gedaan worden als beslist |
80 |
77 |
wordt de video's op YouTube te laten staan. |
81 |
78 |
|
82 |
79 |
*** Google & privacy |
83 |
- | |
84 |
- |
docs/thesis/client-side-scripting.org ¶
1 addition and 1 deletion.
View changes Hide changes
1 |
1 |
Ingewijden zijn bekend met het feit dat JavaScript een Turing-complete |
2 |
2 |
programmeertaal is; je kunt er dus daadwerkelijk programma's mee schrijven. |
3 |
3 |
Een prominent voorbeeld hiervan is Google met haar Google Docs, Sheets, |
4 |
4 |
Presentations, GMail, ... |
5 |
5 |
|
6 |
6 |
Het valt dan natuurlijk op dat binnen Joeni *geen enkele lijn JavaScript |
7 |
7 |
geschreven is*. En dat is ook expres gedaan. |
8 |
8 |
Dat klinkt misschien nogal contra-intuïtief; een volledig programma, dat |
9 |
9 |
hoofdzakelijk gebruikt zal worden via de browser, dat client-side scripting |
10 |
10 |
expres aan zijn neus voorbij laat gaan. |
11 |
11 |
|
12 |
12 |
Hier zijn meerdere redenen voor. Eén van de voornaamste redenen (en eentje die |
13 |
13 |
Google, Facebook, ... allemaal klaarblijkelijk vergeten zijn) is dat een |
14 |
14 |
grondregel van /web development/ is dat je er niet van mag uitgaan dat de |
15 |
15 |
gebruiker JavaScript ondersteunt. |
16 |
16 |
|
17 |
17 |
*Client-side scripting (Css* (niet te verwarren met Cascading Style Sheets, CSS)) |
18 |
18 |
*mag enkel een strikt cosmetisch effect hebben op |
19 |
19 |
een website.* De functionaliteit gaat namelijk compleet verloren als de |
20 |
20 |
gebruiker geen ondersteuning biedt. |
21 |
21 |
|
22 |
22 |
Alhoewel het in de praktijk steeds neerkomt op "JavaScript (JS) dient vermeden te |
23 |
23 |
worden op het web", ga ik enkel spreken over "Client side scripting" (Css), |
24 |
24 |
omdat veel van de problemen die zich met JS zouden voordoen, zich eveneens |
25 |
25 |
zouden voordoen bij eender welke andere taal (Python, Clojure, ...), |
26 |
26 |
als die voor Css gebruikt zou worden. JS is sinds [[http://es6-features.org/][ES6]] een betere taal geworden, |
27 |
27 |
maar de "kwaliteit" van een taal is volledig irrelevant in deze discussie. Het |
28 |
28 |
bespreken van de faciliteiten die JS als programmeertaal biedt wordt in dit |
29 |
29 |
hoofdstuk dus achterwege gelaten. |
30 |
30 |
|
31 |
31 |
Er wordt hier ook enkel gefocust op het gebruik van Css om bepaalde |
32 |
32 |
functionaliteit te laten werken. Css die enkel een cosmetisch effect heeft is |
33 |
33 |
niet het onderwerp van dit stuk, maar wordt eveneens vermeden om aan te tonen |
34 |
34 |
dat een bruikbare web-applicatie ook mooi kan zijn met enkel HTML en CSS. |
35 |
35 |
|
36 |
36 |
*** Verschillende versies |
37 |
37 |
Alles wat netwerkgerelateerd is, moet zich houden aan vooraf opgelegde |
38 |
38 |
standaarden om correct te kunnen communiceren, en met het WWW is dat niet |
39 |
39 |
anders. |
40 |
40 |
|
41 |
41 |
Dit geeft ook een reden om geen Css te gebruiken; op dit moment moet ik |
42 |
42 |
rekening houden met |
43 |
43 |
|
44 |
44 |
- De standaard van HTML(5) en welke tags ondersteund worden |
45 |
45 |
- De standaard van CSS(3) en de ondersteunde /properties/ binnen browsers |
46 |
46 |
|
47 |
47 |
Dit op zich is al een hele klus, en vereist *continu onderhoud van de software*. |
48 |
48 |
|
49 |
49 |
Stel dat men geen website ontwerpt, en /native software/ ontwikkelt, dan hoeft |
50 |
50 |
men enkel rekening te houden met de syntax van de programmeertaal; als het |
51 |
51 |
compileert kan het bij wijze van spreken gebruikt worden.[fn::In de praktijk is het niet zo voor de hand liggend, maar om het punt te maken volstaat dit.] |
52 |
52 |
|
53 |
53 |
Met Css moet men rekening houden met welke onderdelen van de gebruikte |
54 |
54 |
programmeertaal door de browsers wordt ondersteund, en dat is van vitaal belang, |
55 |
55 |
want als het script niet ondersteund wordt, wordt het simpelweg niet uitgevoerd, |
56 |
56 |
met als gevolg dat de website aan functionaliteit moet inboeten. |
57 |
57 |
|
58 |
58 |
Als dit bij HTML of CSS gebeurt (bv. gebruik van [[https://developer.mozilla.org/en-US/docs/Web/HTML/Element/marquee][<marquee>]]), dan kan de browser |
59 |
59 |
nog terugvallen op een standaardwaarde. Dit is ook mogelijk, omdat geen van |
60 |
- | beide een programmeertaal is; men kán onderdelen vervangen zonder een al te |
+ |
60 |
beide een programmeertaal is; men kán onderdelen vervangen zonder een al te |
61 |
61 |
groot risico te lopen om de site kapot te maken. |
62 |
62 |
|
63 |
63 |
Een goed voorbeeld hiervan is het ~<tel>~-element, dat wordt gebruikt om een |
64 |
64 |
telefoonnummer aan te duiden op een webpagina. Op mobiele browsers wordt een |
65 |
65 |
klik hierop behandeld als een telefoongesprek. Op (oudere) desktopbrowsers wordt |
66 |
66 |
dit als gewone tekst weergegeven. |
67 |
67 |
|
68 |
68 |
*** Turing-compleetheid |
69 |
69 |
De aantrekkingskracht van Css schuilt in de [[https://nl.wikipedia.org/wiki/Turingvolledigheid][Turing-compleetheid]]. Dit maakt het tot een |
70 |
70 |
programmeertaal waarin elk mogelijk computerprogramma geprogrammeerd kan worden. |
71 |
71 |
|
72 |
72 |
De grote máár in deze kracht, is dat dat ook een hoop verantwoordelijkheid met |
73 |
73 |
zich meebrengt. Er kunnen fouten in de code sluipen, die de hele website kunnen |
74 |
74 |
doen vastlopen. |
75 |
75 |
|
76 |
76 |
JavaScript heeft dan ook nog de ongelukkige eigenschap dat het een enorm |
77 |
77 |
[[https://en.wikipedia.org/wiki/Strong_and_weak_typing][zwak getypeerde programmeertaal]] is; de taal doet in de achtergrond stille |
78 |
78 |
conversies tussen verschillende types, en geeft liever foute resultaten terug |
79 |
79 |
dan de programmeur te vertellen dat er een fout in de code zit. |
80 |
80 |
|
81 |
81 |
Deze punten gelden natuurlijk ook voor de /server-side/, maar dit is (in |
82 |
82 |
tegenstelling tot Css) absoluut onvermijdelijk om een dergelijke website te |
83 |
83 |
creëren. |
84 |
84 |
Daarnaast zijn er ook een hoop voordelen die men niet heeft bij Css: |
85 |
85 |
|
86 |
86 |
- Vrije keuze van programmeertaal (en mogelijkheid om te linken met andere |
87 |
87 |
software) |
88 |
88 |
- Zekerheid dat, als de software werkt op de ene /client/, die ook voor de |
89 |
89 |
andere /client/ werkt (zie [[Verschillende versies][Verschillende versies]]). |
90 |
90 |
|
91 |
91 |
HTML en CSS zijn geen "volwaardige programmeertalen". HTML is een opmaaktaal, |
92 |
92 |
men beschrijft er dus mee hoe bepaalde onderdelen van de website moeten worden |
93 |
93 |
voorgesteld; als een hyperlink, een paragraaf, ... |
94 |
94 |
CSS laat toe om de stijl van deze opmaak te definiëren, hoe moet een hyperlink |
95 |
95 |
uitzien, ... |
96 |
96 |
|
97 |
97 |
Een fout hierin heeft hoogstens een esthetisch vervelend effect tot gevolg; veel |
98 |
98 |
browsers negeren fouten, en vervangen deze door /fallbacks/. Dit is niet |
99 |
99 |
mogelijk met een programmeertaal; een fout is een fout, en computers zijn niet |
100 |
100 |
in staat om een fout programma zelf te repareren. |
101 |
101 |
|
102 |
102 |
*** Onbeschikbaarheid |
103 |
103 |
Er zijn talloze manieren waarop de aangereikte code niet beschikbaar kan zijn |
104 |
104 |
voor de gebruiker, waardoor een website die afhangt van Css plots zonder |
105 |
105 |
waarschuwing niet meer werkzaam is. Een wilde greep uit de mogelijkheden: |
106 |
106 |
|
107 |
107 |
- De gebruiker heeft een zwakke computer |
108 |
108 |
- De computer heeft een slechte verbinding |
109 |
109 |
- De gebruiker surft via de GSM (een zwakke computer met een slechte verbinding) |
110 |
110 |
- De gebruiker heeft [[https://noscript.net][NoScript]], [[https://www.gnu.org/software/librejs/][GNU LibreJS,]] of een andere extensie die Css blokkeert |
111 |
111 |
- De verbinding wordt onderbroken tijdens het inladen, en de pagina blokkeert |
112 |
112 |
terwijl het tevergeefs wacht op de rest van het script |
113 |
113 |
- De browser van de gebruiker ondersteunt simpelweg geen Css |
114 |
114 |
- De browser van de gebruiker ondersteunt niet de Css-implementatie die op de |
115 |
115 |
website gebruikt wordt (zie [[Verschillende versies]]) |
116 |
116 |
- De website laadt Css in van een externe website, maar er is een fout in het |
117 |
117 |
certificaat, en de browser weigert om de verbinding op te zetten |
118 |
118 |
- ... |
119 |
119 |
|
120 |
120 |
Er hoeft maar één (en slechts één) van deze mogelijkheden op te treden, en *de |
121 |
121 |
volledige website is per direct compleet onbruikbaar*. |
122 |
122 |
|
123 |
123 |
Voor elk van deze mogelijkheden zou met Css een controle moeten worden |
124 |
124 |
ingebouwd, en dan weer voor elke mogelijkheid een oplossing bedacht (want "Het |
125 |
125 |
werkt niet en dat is de schuld van de gebruiker" is geen oplossing). |
126 |
126 |
|
127 |
127 |
Daarentegen, wat als er server-side een fout optreedt? \\ |
128 |
128 |
Veel webframeworks hebben ingebouwde /debugging tools/ die bij fouten direct de |
129 |
129 |
programmeur wijzen op de fout. Django is hier een goed voorbeeld van. |
130 |
130 |
|
131 |
131 |
Daarnaast biedt de betere webserver ook ingebouwde oplossingen om vaak |
132 |
132 |
voorkomende fouten af te handelen (zoals een HTTP 404). In dat geval kan er |
133 |
133 |
gemakkelijk een e-mail naar de ontwikkelaar gestuurd worden, of kan een log |
134 |
134 |
aangemaakt worden. En dit is vaak allemaal /ingebouwd/. |
135 |
135 |
|
136 |
136 |
*** Uitgesteld resultaat |
137 |
137 |
Bestanden over het WWW worden quasi altijd verzonden via [[https://nl.wikipedia.org/wiki/Hypertext_Transfer_Protocol][HTTP]]([[https://nl.wikipedia.org/wiki/HyperText_Transfer_Protocol_Secure][S]]), en de browser |
138 |
138 |
is daarna verantwoordelijk voor het in elkaar steken van alle ontvangen |
139 |
139 |
onderdelen. |
140 |
140 |
|
141 |
141 |
Het handige hieraan, is dat elke browser zelf kan bepalen hoe, en in welke volgorde dit |
142 |
142 |
moet gebeuren, al dan niet in functie van bepaalde instellingen die de gebruiker |
143 |
143 |
zelf kan aanpassen (bv. geen afbeeldingen laden via 4G). |
144 |
144 |
|
145 |
145 |
Css interfereert op haast elk mogelijk niveau met deze werkwijze. Net omdat het |
146 |
146 |
niet op voorhand geweten is wat er zal worden aangepast, of wanneer de code |
147 |
147 |
ingeladen moet worden, is een browser verplicht om vanaf het eerste moment dat |
148 |
148 |
een script gedetecteerd wordt (bv. via de ~<script></script>~-tags), direct de |
149 |
149 |
code te evalueren en uit te voeren, ongeacht hoe lang het duurt of hoe zwaar het is. |
150 |
150 |
|
151 |
151 |
Css breekt ook met het gebruikelijke mantra dat de browser/gebruiker bepaalt hoe |
152 |
152 |
en wat wordt ingeladen. |
153 |
153 |
Vaak betekent dit ook dat de code geëvalueerd moet worden, op dat exacte moment, |
154 |
154 |
vooraleer de rest van de pagina getoond kan worden. \\ |
155 |
155 |
Dit is minder een probleem als Css gebruikt wordt voor het enige waarvoor het |
156 |
156 |
zou gebruikt moeten worden (cosmetische elementen), omdat praktisch alle code dan expres |
157 |
157 |
op het einde van het HTML-document kan worden ingeladen. De website is dan al |
158 |
158 |
bruikbaar vooraleer de code ingeladen moet worden. \\ |
159 |
159 |
Een groeiend aantal gebruikers blokkeert ook expres Css tijdens het surfen op |
160 |
160 |
het web, omdat de snelheidswinsten en sterk verhoogde privacy een waardige |
161 |
161 |
afweging is voor een ietwat minder cosmetisch aangeklede website. Met andere |
162 |
162 |
woorden; zij stellen het resultaat uit voor onbepaalde duur. |
163 |
163 |
|
164 |
164 |
Dit geeft vanzelfsprekend ook problemen als de code niet geoptimaliseerd is, en |
165 |
165 |
daar elke browser de aangereikte Css op een andere manier kan evalueren, is het |
166 |
166 |
onbegonnen werk om voor alle mogelijke implementaties handige optimalisaties |
167 |
167 |
door te voeren. Men beperkt zich natuurlijk meestal tot de populairste |
168 |
168 |
implementaties ([[https://en.wikipedia.org/wiki/WebKit][WebKit]] en [[https://en.wikipedia.org/wiki/Gecko_(software)][Gecko]]). |
169 |
169 |
|
170 |
170 |
_Maar je hoeft vanzelfsprekend niet te optimaliseren, als er geen code is om te optimaliseren._ |
171 |
171 |
|
172 |
172 |
Je zou kunnen zeggen dat deze redenering ook opgaat voor Joeni zelf, wat van |
173 |
173 |
Python gebruik maakt. Maar het gebruikte framework ondersteunt het |
174 |
174 |
[[https://docs.djangoproject.com/en/2.0/topics/cache/][cachen van pagina's]]. Dus eerder geëvalueerde code zal al op voorhand beschikbaar |
175 |
175 |
zijn. Daarbij komt dat de snelheid van een server naar wens kan worden vergroot, |
176 |
176 |
terwijl je bij de gebruiker er van moet uitgaan dat zijn/haar toestel traag is. |
177 |
177 |
De code van de server hoeft ook slechts voor één platform geoptimaliseerd te |
178 |
178 |
worden, dat van de server. |
179 |
179 |
|
180 |
180 |
Uiteindelijk is het resultaat van (foutief) Css-gebruik |
181 |
181 |
sowieso: *Een traag werkende website.* |
182 |
182 |
|
183 |
183 |
*** Verlies van betekenis |
184 |
184 |
Een bepaalde /tag/ in HTML draagt een bepaalde betekenis. ~<a />~ betekent dat dit |
185 |
185 |
een hyperlink is, ~<body />~ betekent dat wat volgt getoond moet worden als de |
186 |
186 |
'inhoud' van de pagina, ~<p />~ duidt op een paragraaf, ... |
187 |
187 |
|
188 |
188 |
Deze betekenis wordt vaak door de browser ten volle benut; Alle links kunnen makkelijk |
189 |
189 |
op voorhand verzameld worden (i.e. Alles wat tussen ~<a />~ staat), wat tussen |
190 |
190 |
~<head />~ staat wordt niet getoond, ... |
191 |
191 |
|
192 |
192 |
*Betekenis opent deuren voor het impliciet infereren van informatie.* Dit is de |
193 |
193 |
reden waarom de tags in HTML (en vooral sinds HTML5) een aanduiding zijn voor |
194 |
194 |
wat de ingesloten data /betekent/; ~<article />~ is een artikel en kan dus los |
195 |
195 |
weergegeven worden van de rest van de pagina, ~<del />~ is iets dat niet |
196 |
196 |
meer relevant is, maar waarschijnlijk toch wel weergegeven moet worden. ~<ol />~ |
197 |
197 |
is een geordende lijst, dus de volgorde van de data is van belang, in |
198 |
198 |
tegenstelling tot ~<ul />~. Er zijn ontelbare voorbeelden te vinden. |
199 |
199 |
|
200 |
200 |
Deze betekenis gaat volledig verloren als onderdelen van de website met Css |
201 |
201 |
worden "nagemaakt". ~<div onclick="hyperlink" />~ zal waarschijnlijk wel |
202 |
202 |
doorlinken naar een website, maar waar dat je in bv. FireFox met een |
203 |
203 |
middelmuisklik een ~<a />~ in een nieuw tabblad kunt openen, zal dit niet werken |
204 |
204 |
met Css. |
205 |
205 |
|
206 |
206 |
*** Conclusie |
207 |
207 |
Het moge duidelijk zijn dat het gebruik van Css om zogenaamde /web apps/ te |
208 |
208 |
maken, fundamenteel een slecht idee is, dat meer problemen voortbrengt dan het |
209 |
209 |
oplost. Alle problemen die sommige websites proberen op te lossen met Css, zijn |
210 |
210 |
makkelijker op te lossen met slechts HTML en CSS (Cascading Style Sheets), en |
211 |
211 |
Client side scripting maakt soms de problemen zelfs erger. |
212 |
212 |
|
213 |
213 |
En zelfs al zouden alle bovenstaande punten onwaar zijn, dan nog is Joeni |
214 |
214 |
het bewijs dat Css geen vereiste is om werkende software te schrijven, die |
215 |
215 |
hoofdzakelijk via het WWW beschikbaar wordt gesteld. |
216 |
216 |
docs/thesis/toekomst.org ¶
5 additions and 1 deletion.
View changes Hide changes
1 |
1 |
Joeni is op dit moment een voorbeeld van een kant-en-klare oplossing voor de problemen die |
2 |
2 |
BlackBoard en het studentendossier stellen aan de UHasselt. |
3 |
3 |
|
4 |
4 |
Maar software is steeds in beweging, en is nooit af. Daarom dat ik hier enkele |
5 |
5 |
punten voorzie omtrent de toekomstige uitbreidingen die aan Joeni zouden kunnen |
6 |
6 |
worden toegevoegd, of aan eender welk ander programma dat als vervanging zou dienen.[fn:still-joeni] |
7 |
7 |
|
8 |
8 |
[fn:still-joeni] Voor het schrijfgemak wordt in dit hoofdstuk gewoon "Joeni" |
9 |
9 |
gebruikt om "een vervangende applicatie" te beschrijven, alhoewel dit eender welk |
10 |
10 |
ander programma kan zijn. Indien het specifiek om Joeni gaat, zal dit ook |
11 |
11 |
duidelijk blijken uit de context. |
12 |
12 |
|
13 |
13 |
*** /Desktop/-applicatie |
14 |
14 |
Op dit moment wordt Joeni gebruikt via een webbrowser, maar dit is zeker niet |
15 |
15 |
wat het eindpunt zou moeten zijn. |
16 |
16 |
|
17 |
17 |
Een website kan onmogelijk gebruik maken van alle mogelijkheden die computers |
18 |
18 |
aan hun gebruikers bieden; ze zijn van nature statische tekstbestanden, die |
19 |
19 |
enkel informatie kunnen doorsturen, en (gestructureerd) via speciale |
20 |
20 |
HTML-formulieren informatie kunnen opvangen. Daar komen dan ook een hoop |
21 |
21 |
beveiligingsproblemen bij kijken, die inherent zijn aan websites. |
22 |
22 |
|
23 |
23 |
Joeni moet een programma worden dat op de computer zelf draait. Veel features |
24 |
24 |
die nu simpelweg niet mogelijk zijn in Joeni, zouden hiermee wel mogelijk |
25 |
25 |
worden: |
26 |
26 |
- Pop-ups die aangeven als er een wijziging is gebeurd in het uurrooster :: Nu |
27 |
27 |
moeten studenten zelf naar die webpagina surfen, er wordt geen proactieve |
28 |
28 |
melding hiervan gemaakt. Veel agendaprogramma's geven hier ook geen melding |
29 |
29 |
van, dus via iCal zal dit ook niet lukken. |
30 |
30 |
- Live chat :: Dit is meer een feature die naar Agora toe gericht is, maar een |
31 |
31 |
live chat is ook technisch niet mogelijk zonder /client-side |
32 |
32 |
scripting/ (vereist bv. (D)AJAX-requests). |
33 |
33 |
Dit zou een uiterst handige toepassing zijn voor |
34 |
34 |
groepswerken, waarvoor studenten nu nog altijd zijn aangewezen op |
35 |
35 |
programma's van derden. |
36 |
36 |
- Offline halen van studiemateriaal :: Het is triviaal, maar Joeni werkt enkel |
37 |
37 |
met een internetverbinding, net zoals *elke webapplicatie* (van de UHasselt). |
38 |
38 |
Een "echt" programma kan al het studiemateriaal, meldingen, opdrachten, ... |
39 |
39 |
downloaden op de computer van de student, zodat dit altijd offline |
40 |
40 |
geraadpleegd kan worden. Het indienen van taken kan dan ook offline |
41 |
41 |
gebeuren, waarna het programma zelf bij de eerstvolgende netwerkverbinding |
42 |
42 |
de taak doorstuurt. |
43 |
43 |
- Veel betere samenhang/snelheid :: Een webapplicatie impliceert dat alle pagina's |
44 |
44 |
telkens opnieuw moeten worden ingeladen, er zit dus altijd een soort van |
45 |
45 |
/delay/ tussen een klik van de gebruiker en de uiteindelijke reactie. De |
46 |
46 |
browser moet ook alles inladen en /renderen/, dus een supersnelle cache |
47 |
47 |
alleen zal nooit het snelheidsprobleem kunnen oplossen. En als de |
48 |
48 |
verbinding wegvalt tijdens het inladen, dan is Joeni plots niet meer |
49 |
49 |
bereikbaar, redelijk frustrerend. Een programma op de computer zelf heeft |
50 |
50 |
al deze problemen niet. Er kan ook gebruik gemaakt worden van een hoop |
51 |
51 |
andere /widgets/ (zoals tabs in hetzelfde venster) die de samenhang verder |
52 |
52 |
kunnen verhogen. |
53 |
53 |
- Dynamische/Directe informatie :: Als de gebruiker een fout maakt bij de |
54 |
54 |
interactie met de website, dan kan hier pas melding van worden gemaakt als |
55 |
55 |
de pagina opnieuw wordt ingeladen. Met een applicatie op de computer kunnen |
56 |
56 |
direct meldingen worden gegeven, en kan het indienen onmogelijk worden |
57 |
57 |
gemaakt totdat de gebruiker alle problemen heeft opgelost. Het geeft ook |
58 |
58 |
zekerheid: Als een knop wordt ingedrukt, dan is er zekerheid dat de |
59 |
59 |
verandering correct werd doorgevoerd. |
60 |
- | - Mogelijkheden voor verbeterde authenticatie en beveiliging :: Op dit moment |
+ |
60 |
van resultaten: Als een docent een student in tweede kans een geslaagd |
+ |
61 |
cijfer wilt geven, maar vergeet de uitslag op "geslaagd" te zetten, dan kan |
+ |
62 |
een gewoon programma hierover direct informeren dat er misschien een fout |
+ |
63 |
gebeurd is. Dat gaat nu niet in Joeni zonder een hoop scripting. |
+ |
64 |
- Mogelijkheden voor verbeterde authenticatie en beveiliging :: Op dit moment |
61 |
65 |
wordt de eigenaar van een account geverifieerd middels een stamnummer en |
62 |
66 |
een wachtwoord. Vergeleken met assymetrische sleutels is dit een redelijk |
63 |
67 |
slechte manier van beveiliging. Het WWW is niet voorzien op ergonomisch |
64 |
68 |
gebruik van bv. PGP-sleutels, maar een gewoon programma kan hiermee |
65 |
69 |
probleemloos overweg. |
66 |
70 |
|
67 |
71 |
De reden dat er voor Joeni toch gekozen is voor een webapplicatie om te |
68 |
72 |
beginnen, is omdat het niet zozeer de bedoeling was dat Joeni "het eindpunt" zou |
69 |
73 |
worden, maar eerder een voorstelling van hoe het eruit zou kunnen zien. Het zou |
70 |
74 |
Joeni ook complexer maken: Rekening houden met dynamische veranderingen, pop-ups |
71 |
75 |
inbouwen (waarvan de API's kunnen verschillen per besturingssysteem), ... Het |
72 |
76 |
maakt het geheel veel moeilijker om te bouwen, maar voegt weinig toe voor deze bachelorproef. |
73 |
77 |
Daarom dat een website het idee van Joeni veel beter overbrengt, maar dan wel in |
74 |
78 |
een statische setting.\\ |
75 |
79 |
Daarbij is een groot deel van de code in de achtergrond (voornamelijk de |
76 |
80 |
databasecode) overdraagbaar, daar een desktopapplicatie sowieso contact zal |
77 |
81 |
moeten onderhouden met een databank. |
78 |
82 |
|
79 |
83 |
*** Herschrijven of onderhouden? |
80 |
84 |
Persoonlijk heb ik bij het zien van bepaalde systemen vaak een indruk van: "Dit |
81 |
85 |
kan beter, en ik weet hoe." Vermoedelijk bestaat er eenzelfde gevoel bij andere |
82 |
86 |
informatici, een drang om iets volledig te herschrijven en "het deze keer goed |
83 |
87 |
te doen". |
84 |
88 |
|
85 |
89 |
Maar eigenlijk moet voor elk onderdeel apart overwogen worden wat op lange |
86 |
90 |
termijn het voordeligst is voor de universiteit zelf. Herschrijven is |
87 |
91 |
aantrekkelijk, maar kan veel tijd kosten en kan onvoorziene fouten met zich |
88 |
92 |
meebrengen. In het ergste geval staat de software hierna zelfs geen stap verder. |
89 |
93 |
Daarnaast is het op z'n minst een beetje arrogant om aan te nemen dat we niet zo |
90 |
94 |
slecht zijn in het programmeren als onze voorganger(s), iedereen maakt immers fouten. |
91 |
95 |
|
92 |
96 |
Het alternatief is de bestaande software onderhouden. Dit kan voordeliger zijn, |
93 |
97 |
voor verschillende redenen: |
94 |
98 |
- Personeel dat de software gebruikt is ermee bekend, en kan gradueel de |
95 |
99 |
evolutie ervan meevolgen, alsook direct feedback geven. Bij een /full rewrite/ |
96 |
100 |
is het altijd wachten tot het klaar is, of totdat er een "MVP"[fn:mvp] bestaat, en dan |
97 |
101 |
nog is het veelal giswerk, getuige de leerstof van het vak Software |
98 |
102 |
Engineering. |
99 |
103 |
- Een beetje triviaal, maar toch: De software is al uitvoerig getest, is al |
100 |
104 |
grotendeels af, en bestaande problemen zijn goed gekend. Er is geen nood aan |
101 |
105 |
het maken van uitvoerige /use cases/, /working drafts/, ... Dat op zich is ook |
102 |
106 |
al een enorme hoeveelheid tijd bespaard. |
103 |
107 |
- Er is een redelijke kans dat deze optie een stuk goedkoper uitvalt dan het |
104 |
108 |
volledig opnieuw schrijven. |
105 |
109 |
|
106 |
110 |
Echter, er zijn enkele voorwaarden aan verbonden: |
107 |
111 |
- De software moet vrij zijn[fn:private-is-free], anders kan er technisch (en juridisch) gezien geen |
108 |
112 |
aanpassing aan gebeuren. |
109 |
113 |
- De software moet ondersteund worden door de gebruikte systemen. Bijvoorbeeld: |
110 |
114 |
Een programma geschreven in Turbo Pascal kan waarschijnlijk niet meer werken |
111 |
115 |
op een modern besturingssysteem, terwijl een programma dat op de Java Virtual |
112 |
116 |
Machine werkt juist nog een lang leven beschoren kan zijn. |
113 |
117 |
- Er moeten programmeurs voor te vinden zijn. Hiermee doel ik op het feit dat |
114 |
118 |
programmeertalen komen en gaan, en zo ook de interesse van mensen om zich |
115 |
119 |
erin te verdiepen: Het is tegenwoordig een stuk moeilijker om een |
116 |
120 |
COBOL-programmeur te vinden dan een Javaprogrammeur. Als het vinden van |
117 |
121 |
gekwalificeerd personeel te moeilijk is, dan is onderhoud waarschijnlijk |
118 |
122 |
gewoon niet meer mogelijk. |
119 |
123 |
|
120 |
124 |
Een mogelijk voorstel is om een lijst op te stellen van beslissende factoren, |
121 |
125 |
samen met de juiste personen. Dan kunnen die factoren getoetst worden aan alle |
122 |
126 |
gebruikte software voor de UHasselt, en dan kan er individueel beslist worden |
123 |
127 |
welke software vervangen wordt, en dewelke onderhouden wordt. |
124 |
128 |
|
125 |
129 |
[fn:mvp] /Minimum Viable Product/: Een marketingterm waarmee een prototype van |
126 |
130 |
een product of werk wordt bedoeld waarmee de klant een eerste indruk kan krijgen |
127 |
131 |
van het uiteindelijke geheel. |
128 |
132 |
|
129 |
133 |
[fn:private-is-free] Software die de UHasselt zelf geschreven heeft, is per |
130 |
134 |
definitie ook vrij. |
131 |
135 |