Commit 0b6968b4 authored by Martin Mareš's avatar Martin Mareš
Browse files

All URLs related to courses include also the semester ident

parent 5d71c534
......@@ -209,7 +209,7 @@ def enroll():
return render_template('join.html', form=form, error=None)
token = form.token.data
db_query("SELECT * FROM owl_courses WHERE enroll_token=%s", (token,))
db_query("SELECT c.*, s.ident AS sident FROM owl_courses c JOIN owl_semesters s USING(semid) WHERE enroll_token=%s", (token,))
course = db.fetchone()
if not course:
app.logger.info('Invalid enroll token for uid=%d', g.uid)
......@@ -224,20 +224,20 @@ def enroll():
(g.uid, course.cid))
db_connection.commit()
return redirect(url_for('course_index', cident=course.ident))
return redirect(url_for('course_index', sident=course.sident, cident=course.ident))
def course_init(cident):
def course_init(sident, cident):
if not have_session_p():
return login_redirect(current=True)
db_query("""
SELECT c.*, s.ident AS sem_ident
SELECT c.*, s.ident AS sident
FROM owl_courses c
JOIN owl_semesters s USING(semid)
WHERE c.ident=%s
WHERE s.ident=%s AND c.ident=%s
""",
(cident,))
(sident, cident))
g.course = db.fetchone()
if not g.course:
return "No such course", HTTPStatus.NOT_FOUND
......@@ -255,8 +255,8 @@ def course_init(cident):
return None
def topic_init(cident, tident):
err = course_init(cident)
def topic_init(sident, cident, tident):
err = course_init(sident, cident)
if err:
return err
......@@ -294,9 +294,9 @@ def must_be_admin():
return None
@app.route('/c/<cident>/')
def course_index(cident):
err = course_init(cident)
@app.route('/c/<sident>/<cident>/')
def course_index(sident, cident):
err = course_init(sident, cident)
if err:
return err
......@@ -404,10 +404,10 @@ class TopicPostForm(FlaskForm):
ack_time = wtforms.HiddenField()
@app.route('/c/<cident>/<tident>/', methods=('GET', 'POST'))
@app.route('/c/<cident>/<tident>/<int:student_uid>/', methods=('GET', 'POST'))
def topic_index(cident, tident, student_uid=None):
err = topic_init(cident, tident)
@app.route('/c/<sident>/<cident>/<tident>/', methods=('GET', 'POST'))
@app.route('/c/<sident>/<cident>/<tident>/<int:student_uid>/', methods=('GET', 'POST'))
def topic_index(sident, cident, tident, student_uid=None):
err = topic_init(sident, cident, tident)
if err:
return err
......@@ -522,16 +522,17 @@ def topic_post(form, student_uid):
if new_post:
wake_up_mule()
return redirect(url_for('topic_index',
sident=g.course.sident,
cident=g.course.ident,
tident=g.topic.ident,
student_uid=(student_uid if student_uid != g.uid and student_uid >= 0 else None)
) + "#p" + str(new_post.pid))
elif g.is_teacher:
return redirect(url_for('teacher', cident=g.course.ident))
return redirect(url_for('teacher', sident=g.course.sident, cident=g.course.ident))
elif g.is_grader:
return redirect(url_for('topic_student_grade', cident=g.course.ident, tident=g.topic.ident))
return redirect(url_for('topic_student_grade', sident=g.course.sident, cident=g.course.ident, tident=g.topic.ident))
else:
return redirect(url_for('course_index', cident=g.course.ident))
return redirect(url_for('course_index', sident=g.course.sident, cident=g.course.ident))
class EditPostForm(FlaskForm):
......@@ -552,9 +553,9 @@ def edit_allowed_p(post):
post.author_uid == g.uid and g.topic.public)
@app.route('/c/<cident>/<tident>/grade')
def topic_student_grade(cident=None, tident=None):
err = topic_init(cident, tident)
@app.route('/c/<sident>/<cident>/<tident>/grade')
def topic_student_grade(sident=None, cident=None, tident=None):
err = topic_init(sident, cident, tident)
if err:
return err
......@@ -613,9 +614,9 @@ def topic_student_grade(cident=None, tident=None):
return render_template('topic-grade.html', students=students, solutions=solutions)
@app.route('/post/<cident>/<int:pid>/', methods=('GET', 'POST'))
def edit_post(cident, pid):
err = course_init(cident)
@app.route('/post/<sident>/<cident>/<int:pid>/', methods=('GET', 'POST'))
def edit_post(sident, cident, pid):
err = course_init(sident, cident)
if err:
return err
......@@ -647,7 +648,7 @@ def edit_post(cident, pid):
student_uid = post.target_uid
else:
student_uid = None
return_to = url_for('topic_index', cident=g.course.ident, tident=g.topic.ident, student_uid=student_uid)
return_to = url_for('topic_index', sident=g.course.sident, cident=g.course.ident, tident=g.topic.ident, student_uid=student_uid)
if form.delete.data:
if g.is_teacher:
......@@ -702,21 +703,21 @@ class TSolution:
last_seen_by_teacher: datetime.datetime
@app.route('/teacher/c/<cident>/')
@app.route('/teacher/s/<semident>/')
def teacher(cident=None, semident=None):
@app.route('/teacher/c/<sident>/<cident>/')
@app.route('/teacher/s/<sident>/')
def teacher(sident, cident=None):
if not have_session_p():
return login_redirect(current=True)
db_query("CREATE TEMPORARY TABLE tmp_cids (cid int) ON COMMIT DROP");
if cident is not None:
err = course_init(cident)
err = course_init(sident, cident)
if err:
return err
db_query("INSERT INTO tmp_cids VALUES(%s)", (g.course.cid,))
else:
db_query("SELECT * FROM owl_semesters WHERE ident=%s", (semident,))
db_query("SELECT * FROM owl_semesters WHERE ident=%s", (sident,))
semester = db.fetchone()
if not semester:
return "No such semester", HTTPStatus.NOT_FOUND
......@@ -732,10 +733,11 @@ def teacher(cident=None, semident=None):
""", (g.uid, semester.semid))
db_query("""
SELECT *
FROM owl_courses
SELECT c.*, s.ident AS sident
FROM owl_courses c
JOIN owl_semesters s USING(semid)
WHERE cid IN (SELECT cid FROM tmp_cids)
ORDER BY ident
ORDER BY c.ident
""")
courses = {}
......@@ -899,18 +901,18 @@ def serve_file(name):
### Exports ###
@app.route('/teacher/c/<cident>/results.json')
def results_json(cident):
err = course_init(cident) or must_be_teacher()
@app.route('/teacher/c/<sident>/<cident>/results.json')
def results_json(sident, cident):
err = course_init(sident, cident) or must_be_teacher()
if err:
return err
return export_points('json')
@app.route('/teacher/c/<cident>/results.csv')
def results_csv(cident):
err = course_init(cident) or must_be_teacher()
@app.route('/teacher/c/<sident>/<cident>/results.csv')
def results_csv(sident, cident):
err = course_init(sident, cident) or must_be_teacher()
if err:
return err
......@@ -1035,9 +1037,9 @@ def user_settings():
### Administration ###
@app.route('/admin/topics/<cident>/')
def admin_topics(cident):
err = course_init(cident) or must_be_teacher()
@app.route('/admin/topics/<sident>/<cident>/')
def admin_topics(sident, cident):
err = course_init(sident, cident) or must_be_teacher()
if err:
return err
......@@ -1062,9 +1064,9 @@ class AssignGraderForm(FlaskForm):
return True
@app.route('/admin/topics/<cident>/graders/<tid>', methods=('GET', 'POST'))
def admin_topic_graders(cident, tid):
err = course_init(cident) or must_be_teacher()
@app.route('/admin/topics/<sident>/<cident>/graders/<tid>', methods=('GET', 'POST'))
def admin_topic_graders(sident, cident, tid):
err = course_init(sident, cident) or must_be_teacher()
if err:
return err
......@@ -1099,7 +1101,7 @@ def admin_topic_graders(cident, tid):
db_query('DELETE FROM owl_student_graders WHERE tid=%s AND uid=%s', (topic.tid, form.uid.data))
db_connection.commit()
return redirect(url_for('admin_topic_graders', cident=cident, tid=tid))
return redirect(url_for('admin_topic_graders', sident=sident, cident=cident, tid=tid))
else:
db_query("""
SELECT s.uid, s.full_name,
......@@ -1146,11 +1148,11 @@ class EditTopicForm(FlaskForm):
return True
@app.route('/admin/topics/<cident>/edit/<int:tid>', methods=('GET', 'POST'))
@app.route('/admin/topics/<cident>/new', methods=('GET', 'POST'))
@app.route('/admin/topics/<cident>/copy/<int:copy_tid>', methods=('GET', 'POST'))
def admin_edit_topic(cident, tid=None, copy_tid=None):
err = course_init(cident) or must_be_teacher()
@app.route('/admin/topics/<sident>/<cident>/edit/<int:tid>', methods=('GET', 'POST'))
@app.route('/admin/topics/<sident>/<cident>/new', methods=('GET', 'POST'))
@app.route('/admin/topics/<sident>/<cident>/copy/<int:copy_tid>', methods=('GET', 'POST'))
def admin_edit_topic(sident, cident, tid=None, copy_tid=None):
err = course_init(sident, cident) or must_be_teacher()
if err:
return err
......@@ -1167,7 +1169,7 @@ def admin_edit_topic(cident, tid=None, copy_tid=None):
db_query("DELETE FROM owl_topics WHERE tid=%s", (tid,))
db_connection.commit()
flash('Topic deleted.', 'info')
return redirect(url_for('admin_topics', cident=cident))
return redirect(url_for('admin_topics', sident=sident, cident=cident))
if tid is None:
db_query("INSERT INTO owl_topics(cid, type) VALUES(%s, 'H') RETURNING tid", (g.course.cid,))
......@@ -1216,7 +1218,7 @@ def admin_edit_topic(cident, tid=None, copy_tid=None):
wake_up_mule()
flash('Topic saved.', 'info')
return redirect(url_for('admin_topics', cident=cident))
return redirect(url_for('admin_topics', sident=sident, cident=cident))
else:
post_count = 0
if tid is None and copy_tid is None:
......@@ -1241,9 +1243,9 @@ def admin_edit_topic(cident, tid=None, copy_tid=None):
return render_template('admin-edit-topic.html', form=form, tid=tid, copy_tid=copy_tid, post_count=post_count)
@app.route('/admin/course/<cident>/')
def admin_course(cident):
err = course_init(cident) or must_be_teacher()
@app.route('/admin/course/<sident>/<cident>/')
def admin_course(sident, cident):
err = course_init(sident, cident) or must_be_teacher()
if err:
return err
......@@ -1268,7 +1270,7 @@ def admin_courses():
if err:
return err
db_query("SELECT c.*, s.ident AS sem_ident FROM owl_courses c JOIN owl_semesters s USING(semid) ORDER BY s.rank, c.ident");
db_query("SELECT c.*, s.ident AS sident FROM owl_courses c JOIN owl_semesters s USING(semid) ORDER BY s.rank, c.ident");
courses = db.fetchall()
db_query("""
......@@ -1590,7 +1592,7 @@ def send_notify_post(post):
if not topic.public:
return
db_query("SELECT * FROM owl_courses WHERE cid=%s", (topic.cid,))
db_query("SELECT c.*, s.ident AS sident FROM owl_courses c JOIN owl_semesters s USING(semid) WHERE cid=%s", (topic.cid,))
course = db.fetchone()
db_query("SELECT * FROM owl_users WHERE uid=%s", (post.author_uid,))
......@@ -1662,7 +1664,7 @@ def send_notify_to_dest(post, topic, course, author, target, dest):
]
if post.modified:
h.append(('Updated', post.modified.replace(microsecond=0).astimezone().strftime("%Y-%m-%d %H:%M:%S")))
h.append(('URL', url_for('topic_index', cident=course.ident, tident=topic.ident, student_uid=target_uid, _external=True, _scheme='https')))
h.append(('URL', url_for('topic_index', sident=course.ident, cident=course.ident, tident=topic.ident, student_uid=target_uid, _external=True, _scheme='https')))
h.append(('Points', post.points if post.points is not None else '-'))
head = "\n".join(["{:12} {}".format(p[0] + ':', p[1]) for p in h]) + "\n\n"
body = post.comment or ""
......
......@@ -11,6 +11,6 @@
</table>
<div class=buttons>
<a class=button href='{{ url_for('course_index', cident=g.course.ident) }}'>Back to the course&hellip;</a>
<a class=button href='{{ url_for('course_index', sident=g.course.sident, cident=g.course.ident) }}'>Back to the course&hellip;</a>
</div>
{% endblock %}
......@@ -12,9 +12,9 @@
</thead>
{% for c in courses %}
<tr>
<td>{{ c.sem_ident }}
<td>{{ c.sident }}
<td style='white-space: nowrap'>{{ c.ident }}
<td><a href='{{ url_for('course_index', cident=c.ident) }}'>{{ c.name }}</a>
<td><a href='{{ url_for('course_index', sident=c.sident, cident=c.ident) }}'>{{ c.name }}</a>
{% if c.cid in teachers %}
<td>{{ teachers[c.cid]|sort|join(", ") }}
{% else %}
......
......@@ -26,7 +26,7 @@
</table>
<p class=buttons>{{ form.submit(class='ok') }}
{% if tid != None %}
<a class=button href='{{ url_for('admin_edit_topic', cident=g.course.ident, copy_tid=tid) }}'>Copy</a>
<a class=button href='{{ url_for('admin_edit_topic', sident=g.course.sident, cident=g.course.ident, copy_tid=tid) }}'>Copy</a>
<p>{{ form.delete(class='danger') }}&nbsp;&nbsp;(including {{ post_count }} posts)
{% endif %}
</form>
......
......@@ -3,7 +3,7 @@
<h2>Student graders of {{ topic.title }}</h2>
<div class="buttons">
<span class="button"><a href="{{url_for('admin_topics', cident=g.course.ident)}}">Back</a></span>
<span class="button"><a href="{{url_for('admin_topics', sident=g.course.sident, cident=g.course.ident)}}">Back</a></span>
</div>
<h3>Assigned graders</h3>
......
......@@ -13,10 +13,10 @@
{% set cls = "thidden" %}
{% endif %}
<tr class={{ cls }}>
<td><a href='{{ url_for('admin_edit_topic', cident=g.course.ident, tid=t.tid) }}'>{{ t.rank }}</a>
<td><a href='{{ url_for('admin_edit_topic', sident=g.course.sident, cident=g.course.ident, tid=t.tid) }}'>{{ t.rank }}</a>
<td>{{ t.ident or "" }}
{% if t.ident %}
<td><a href='{{ url_for('topic_index', cident=g.course.ident, tident=t.ident) }}'>{{ t.title }}</a>
<td><a href='{{ url_for('topic_index', sident=g.course.sident, cident=g.course.ident, tident=t.ident) }}'>{{ t.title }}</a>
{% else %}
<td>{{ t.title }}
{% endif %}
......@@ -24,13 +24,13 @@
<td>{{ t.deadline|reltimeformat }}
<td class=pts>{{ t.max_points if t.max_points != None else "" }}
{% if g.course.student_grading %}
<td>{% if t.type == 'T' %}<a href='{{ url_for('admin_topic_graders', cident=g.course.ident, tid=t.tid) }}'>Assign</a>{% endif %}
<td>{% if t.type == 'T' %}<a href='{{ url_for('admin_topic_graders', sident=g.course.sident, cident=g.course.ident, tid=t.tid) }}'>Assign</a>{% endif %}
{% endif %}
{% endfor %}
</table>
<div class=buttons>
<a class=button href='{{ url_for('admin_edit_topic', cident=g.course.ident) }}'>New topic</a>
<a class=button href='{{ url_for('course_index', cident=g.course.ident) }}'>Back to the course</a>
<a class=button href='{{ url_for('admin_edit_topic', sident=g.course.sident, cident=g.course.ident) }}'>New topic</a>
<a class=button href='{{ url_for('course_index', sident=g.course.sident, cident=g.course.ident) }}'>Back to the course</a>
</div>
{% endblock %}
......@@ -7,9 +7,9 @@
{% if g.is_teacher %}
<div class=buttons>
<a class=button href='{{ url_for('admin_topics', cident=g.course.ident) }}'>Edit topics</a>
<a class=button href='{{ url_for('teacher', cident=g.course.ident) }}'>Teacher's summary</a>
<a class=button href='{{ url_for('admin_course', cident=g.course.ident) }}'>Details</a>
<a class=button href='{{ url_for('admin_topics', sident=g.course.sident, cident=g.course.ident) }}'>Edit topics</a>
<a class=button href='{{ url_for('teacher', sident=g.course.sident, cident=g.course.ident) }}'>Teacher's summary</a>
<a class=button href='{{ url_for('admin_course', sident=g.course.sident, cident=g.course.ident) }}'>Details</a>
</div>
{% endif %}
......@@ -30,13 +30,13 @@
{% else %}
{% set cls = 'told' %}
{% endif %}
<tr class={{ cls }}><td><a href="{{ url_for('topic_index', cident=g.course.ident, tident=t.ident) }}">{{ t.title }}</a>
<tr class={{ cls }}><td><a href="{{ url_for('topic_index', sident=g.course.sident, cident=g.course.ident, tident=t.ident) }}">{{ t.title }}</a>
<td>{{ t.deadline|reltimeformat }}
<td class=pts>{{ t.points if t.points != None else "" }}
<td class=pts>{{ t.max_points if t.max_points != None else "" }}
{% if is_grader %}
<td>{% if t.is_grader %}
<a href="{{ url_for('topic_student_grade', cident=g.course.ident, tident=t.ident) }}">Grade</a>
<a href="{{ url_for('topic_student_grade', sident=g.course.sident, cident=g.course.ident, tident=t.ident) }}">Grade</a>
{% endif %}
{% endif %}
{% else %}
......
......@@ -5,13 +5,13 @@
<h2>{{ s.name }}</h2>
<ul>
{% for c in courses[s.semid] %}
<li><a href="{{ url_for('course_index', cident=c.ident) }}">{{ c.name }}</a>{% if c.is_teacher %} (teacher){% endif %}
<li><a href="{{ url_for('course_index', sident=s.ident, cident=c.ident) }}">{{ c.name }}</a>{% if c.is_teacher %} (teacher){% endif %}
{% endfor %}
{% if loop.first %}
<li><a href='{{ url_for('enroll') }}'>Join a new course</a>
{% endif %}
{% if sem_teacher[s.semid] %}
<li><a href='{{ url_for('teacher', semident=s.ident) }}'>Teacher's summary</a>
<li><a href='{{ url_for('teacher', sident=s.ident) }}'>Teacher's summary</a>
{% endif %}
</ul>
{% endif %}
......
......@@ -4,7 +4,7 @@
<h2>Teacher's Summary</h2>
{% for c in courses.values() %}
<h3>{{ c.name }} (<a href='{{ url_for('course_index', cident=c.ident) }}'>{{ c.ident }}</a>)</h3>
<h3>{{ c.name }} (<a href='{{ url_for('course_index', sident=c.sident, cident=c.ident) }}'>{{ c.ident }}</a>)</h3>
<table class=results>
<tr><th class='tbeforehdr'>
......@@ -21,7 +21,7 @@
{% do cls.append("tbeforehdr") %}
{% endif %}
<th class='{{ cls|join(" ") }}' title='{{ t.title }}{% if t.deadline != None %} [{{ t.deadline|reltimeformat }}]{% endif %}'>
<a href='{{ url_for('topic_index', cident=c.ident, tident=t.ident) }}'>{{ t.ident }}</a>
<a href='{{ url_for('topic_index', sident=c.sident, cident=c.ident, tident=t.ident) }}'>{{ t.ident }}</a>
{% endfor %}
<th>Σ
<tr><th class='tbeforehdr'>max.
......@@ -46,7 +46,7 @@
{% do cls.append("snull") %}
{% if t.type == 'A' %}
{% do cls.append("pts") %}
<td class='{{ cls|join(" ") }}'><a href='{{ url_for('topic_index', cident=c.ident, tident=t.ident, student_uid=s.uid) }}'>+</a>
<td class='{{ cls|join(" ") }}'><a href='{{ url_for('topic_index', sident=c.sident, cident=c.ident, tident=t.ident, student_uid=s.uid) }}'>+</a>
{% else %}
<td class='{{ cls|join(" ") }}'>
{% endif %}
......@@ -61,7 +61,7 @@
{% else %}
{% do cls.append("sold") %}
{% endif %}
<td class="{{ cls|join(" ") }}"><a href='{{ url_for('topic_index', cident=c.ident, tident=t.ident, student_uid=s.uid) }}'>
<td class="{{ cls|join(" ") }}"><a href='{{ url_for('topic_index', sident=c.sident, cident=c.ident, tident=t.ident, student_uid=s.uid) }}'>
{% if sol.points != None %}
{{ sol.points }}
{% else %}
......@@ -75,8 +75,8 @@
</table>
<p>Download as
<a href='{{ url_for('results_json', cident=c.ident) }}'>JSON</a>,
<a href='{{ url_for('results_csv', cident=c.ident) }}'>CSV</a>.
<a href='{{ url_for('results_json', sident=c.sident, cident=c.ident) }}'>JSON</a>,
<a href='{{ url_for('results_csv', sident=c.sident, cident=c.ident) }}'>CSV</a>.
{% endfor %}
{% endblock %}
......@@ -5,7 +5,7 @@
<h2>{{c.name}}</h2>
<div class="buttons">
<span class="button"><a href='{{ url_for('course_index', cident=c.ident) }}'>Return to course</a></span>
<span class="button"><a href='{{ url_for('course_index', sident=c.sident, cident=c.ident) }}'>Return to course</a></span>
</div>
<h3>Grade {{t.title}}</h3>
......@@ -33,7 +33,7 @@
{% else %}
{% do cls.append("sold") %}
{% endif %}
<td class="{{ cls|join(" ") }}"><a href='{{ url_for('topic_index', cident=c.ident, tident=t.ident, student_uid=s.uid) }}'>
<td class="{{ cls|join(" ") }}"><a href='{{ url_for('topic_index', sident=c.sident, cident=c.ident, tident=t.ident, student_uid=s.uid) }}'>
{% if sol.points != None %}
{{ sol.points }}
{% else %}
......
......@@ -8,12 +8,12 @@
<h2>{{ g.course.name }}</h2>
<div class="buttons">
<a class="button" href='{{ url_for('course_index', cident=g.course.ident) }}'>Back to the course</a>
<a class="button" href='{{ url_for('course_index', sident=g.course.sident, cident=g.course.ident) }}'>Back to the course</a>
{% if g.is_teacher %}
<a class="button" href='{{ url_for('teacher', cident=g.course.ident) }}'>Teacher's summary</a>
<a class="button" href='{{ url_for('admin_edit_topic', cident=g.course.ident, tid=g.topic.tid) }}'>Edit topic</a>
<a class="button" href='{{ url_for('teacher', sident=g.course.sident, cident=g.course.ident) }}'>Teacher's summary</a>
<a class="button" href='{{ url_for('admin_edit_topic', sident=g.course.sident, cident=g.course.ident, tid=g.topic.tid) }}'>Edit topic</a>
{% elif g.is_grader %}
<a class="button" href='{{ url_for('topic_student_grade', cident=g.course.ident, tident=g.topic.ident) }}'>Grade</a>
<a class="button" href='{{ url_for('topic_student_grade', sident=g.course.sident, cident=g.course.ident, tident=g.topic.ident) }}'>Grade</a>
{% endif %}
</div>
......@@ -57,7 +57,7 @@
<span class=phpast>(after deadline)</span>
{% endif %}
{% if g.is_teacher or p.author_uid == g.uid %}
<a href='{{ url_for('edit_post', cident=g.course.ident, pid=p.pid) }}'>edit</a>
<a href='{{ url_for('edit_post', sident=g.course.sident, cident=g.course.ident, pid=p.pid) }}'>edit</a>
{% endif %}
<a href="#comment" class="preply">reply</a>
{% if p.comment != None %}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment