diff --git a/mo/imports.py b/mo/imports.py
index 72c7b7b3dc98fdff4878118727dd51225f15254a..7cedac5decae24c86d4af3dbaf16d567b72a802f 100644
--- a/mo/imports.py
+++ b/mo/imports.py
@@ -670,7 +670,7 @@ class PointsImport(Import):
                 return self.error('Soutěžící nesoutěží v této oblasti')
 
         rights = self.gatekeeper.rights_for_contest(pion.contest)
-        if not rights.can_edit_points(self.round):
+        if not rights.can_edit_points(self.task.round_part):
             return self.error('Nemáte právo na úpravu bodů')
 
         user = pion.user
@@ -682,7 +682,7 @@ class PointsImport(Import):
                 return
             if not self.allow_add_del:
                 return self.error('Tento soutěžící úlohu neodevzdal')
-            if not rights.can_upload_solutions(round):
+            if not rights.can_upload_solutions(self.task.round_part):
                 return self.error('Nemáte právo na zakládání nových řešení')
             sol = db.Solution(user_id=user_id, task_id=task_id)
             sess.add(sol)
@@ -698,7 +698,7 @@ class PointsImport(Import):
                 return self.error('Tento soutěžící úlohu odevzdal')
             if sol.final_submit is not None or sol.final_feedback is not None:
                 return self.error('Nelze smazat řešení, ke kterému existují odevzdané soubory')
-            if not rights.can_upload_solutions(round):
+            if not rights.can_upload_solutions(self.task.round_part):
                 return self.error('Nemáte právo na mazání řešení')
             logger.info(f'Import: Smazáno řešení user=#{user_id} task=#{task_id}')
             mo.util.log(
diff --git a/mo/jobs/submit.py b/mo/jobs/submit.py
index 019b907402a1c5ebe48b257dd9603eaed06a68ae..8bc74947ccb0858dbc50d78a4897c76bb548a091 100644
--- a/mo/jobs/submit.py
+++ b/mo/jobs/submit.py
@@ -227,7 +227,9 @@ def handle_upload_feedback(the_job: TheJob):
             contest_dict[user.user_id] = contest
             site_id_dict[user.user_id] = pion.place_id
             rr = the_job.gatekeeper.rights_for_contest(contest)
-            user_rights[user.user_id] = rr.can_upload_feedback(round)
+            user_rights[user.user_id] = {
+                part.round_part_id: rr.can_upload_feedback(part) for part in round.parts
+            }
 
         for f in files:
             f.user = user_dict[f.user_id]
@@ -237,8 +239,8 @@ def handle_upload_feedback(the_job: TheJob):
                 the_job.error(f'{f.file_name}: Účastník leží mimo vybranou soutěž')
             elif only_site_id is not None and site_id_dict[f.user_id] != only_site_id:
                 the_job.error(f'{f.file_name}: Účastník leží mimo vybrané soutěžní místo')
-            elif not user_rights[f.user_id]:
-                the_job.error(f'{f.file_name}: K tomuto účastníkovi nemáte dostatečná oprávnění')
+            elif not user_rights[f.user_id][f.task.round_part_id]:
+                the_job.error(f'{f.file_name}: K tomuto účastníkovi a úloze nemáte dostatečná oprávnění')
 
     def process_file(fb: UploadFeedback) -> bool:
         assert fb.user and fb.task
diff --git a/mo/web/org_score.py b/mo/web/org_score.py
index 4925de52983b4623069b642da1d8207bc0d6bc4a..ed0b0dccfde0bc57b1dae33486a8eb21607d0662 100644
--- a/mo/web/org_score.py
+++ b/mo/web/org_score.py
@@ -127,7 +127,7 @@ def org_score(round_id: Optional[int] = None, contest_id: Optional[int] = None):
                 url_for('org_contest_task', contest_id=contest_id, task_id=task.task_id),
                 task.code
             )
-            if rr.can_edit_points(round):
+            if rr.can_edit_points(task.round_part):
                 title += ' <a href="{}" title="Editovat body" class="icon">✎</a>'.format(
                     url_for('org_contest_task_points', contest_id=contest_id, task_id=task.task_id),
                 )
diff --git a/mo/web/templates/org_contest_solutions.html b/mo/web/templates/org_contest_solutions.html
index dcb73a6f713c7b2386521b024525a0d7ee0ba0d6..6ca24602703e717c46bddc3298458820bb7db747 100644
--- a/mo/web/templates/org_contest_solutions.html
+++ b/mo/web/templates/org_contest_solutions.html
@@ -69,7 +69,7 @@ konkrétní úlohu. Symbol <span class="icon">🗐</span> značí, že existuje
 				{% set sol = tasks_sols[task.task_id][u.user_id] %}
 				{% if sol.final_submit_obj %}
 					{% set p = sol.final_submit_obj %}
-					{% set late = p.check_deadline(round) %}
+					{% set late = p.check_deadline(task.round_part) %}
 					<td class="sol{% if late or p.broken %} sol-warn{% endif %}">
 						<a href="{{ paper_link(u, p) }}" title="{{ p.uploaded_at|timeformat }}{% if p.broken %} - nekorektní PDF{% endif %}{% if p.pages != None %} - {{ p.pages|inflected('stránka', 'stránky', 'stránek') }}{% endif %}{% if late %} - {{ late }}{% endif %}">🖺</a>
 						{% set key = (u.user_id, task.task_id, "solution") %}
diff --git a/mo/web/templates/org_submit_list.html b/mo/web/templates/org_submit_list.html
index 63c9051133f7b3fe15ce6c9eae04241ddef24790..d6f4f2454e17d777f42534956cba595d8354b482 100644
--- a/mo/web/templates/org_submit_list.html
+++ b/mo/web/templates/org_submit_list.html
@@ -61,7 +61,7 @@ Existuje více než jedna verze řešení, finální je podbarvená.
 		{% set active_sol_id = None %}
 	{% endif %}
 	{% for p in sol_papers %}
-		{% set late = p.check_deadline(sc.round) %}
+		{% set late = p.check_deadline(sc.task.round_part) %}
 		<tr{% if p.paper_id == active_sol_id %} class='sol-active'{% endif %}>
 			<td{% if late %} class='sol-warn'{% endif %}>{{ p.uploaded_at|timeformat }}
 			<td>{% if p.broken %}nekorektní PDF{% else %}{{ p.pages|or_dash }}{% endif %}
diff --git a/mo/web/templates/parts/org_solution_table.html b/mo/web/templates/parts/org_solution_table.html
index 150d77ecb0f50d4af978c31b7e65e4557fa9c949..a91f604c954c09770807f7ffda2af7c238e32862 100644
--- a/mo/web/templates/parts/org_solution_table.html
+++ b/mo/web/templates/parts/org_solution_table.html
@@ -47,7 +47,7 @@ finální (ve výchozím stavu poslední nahrané).{% elif sc.allow_upload_solut
 		{% if sol %}
 		<td>{% if sol.final_submit_obj %}
 			{% set p = sol.final_submit_obj %}
-			{% set late = p.check_deadline(round) %}
+			{% set late = p.check_deadline(task.round_part) %}
 			{% if late %}<span class='sol-warn icon' title="{{ late }}">⚠</span>{% endif %}
 			<a href='{{ paper_link(u, p) }}'>
 				{{- p.uploaded_at|timeformat }}
diff --git a/mo/web/user.py b/mo/web/user.py
index f4ac0297b3e72e73939b74ce80e9676319ac14bf..a0b79284f121092e75ac3b034973828efb11eafa 100644
--- a/mo/web/user.py
+++ b/mo/web/user.py
@@ -85,15 +85,19 @@ def user_contest(id: int):
     )
 
 
-@app.route('/user/contest/<int:id>/task-statement/zadani.pdf')
-def user_task_statement(id: int):
+@app.route('/user/contest/<int:id>/part/<int:part_id>/task-statement/zadani.pdf')
+def user_task_statement(id: int, part_id: int):
     contest = get_contest(id)
 
-    if not contest.round.task_statement_available():
+    round_part = db.get_session().query(db.RoundPart).get(part_id)
+    if not round_part or round_part.round_id != contest.round_id:
+        raise werkzeug.exceptions.NotFound()
+
+    if not round_part.task_statement_available():
         logger.warn(f'Účastník #{g.user.user_id} chce zadání, na které nemá právo')
         raise werkzeug.exceptions.Forbidden()
 
-    return mo.web.util.send_task_statement(contest.round)
+    return mo.web.util.send_task_statement(round_part)
 
 
 class SubmitForm(FlaskForm):
diff --git a/mo/web/util.py b/mo/web/util.py
index 56dc2e9b494bbeb79f825932bde89c7c98d6f397..31ffd6d2b028566f087d063bb2667581097916e0 100644
--- a/mo/web/util.py
+++ b/mo/web/util.py
@@ -40,9 +40,9 @@ class PagerForm(FlaskForm):
         return (count, query)
 
 
-def send_task_statement(round: db.Round) -> Response:
-    assert round.tasks_file is not None
-    file = os.path.join(mo.util.data_dir('statements'), round.tasks_file)
+def send_task_statement(round_part: db.RoundPart) -> Response:
+    assert round_part.tasks_file is not None
+    file = os.path.join(mo.util.data_dir('statements'), round_part.tasks_file)
     if os.path.isfile(file):
         return send_file(file, mimetype='application/pdf')
     else: