diff --git a/mo/web/__init__.py b/mo/web/__init__.py
index a219a25de57df98b9a44b46a46e7378160592623..26a26e7fd08743fd24987dae5bd16cb8a273576a 100644
--- a/mo/web/__init__.py
+++ b/mo/web/__init__.py
@@ -63,4 +63,5 @@ app.before_request(init_request)
 # Většina webu je v samostatných modulech
 import mo.web.main
 import mo.web.org
+import mo.web.org_users
 import mo.web.menu
diff --git a/mo/web/menu.py b/mo/web/menu.py
index 077e4b0d90feac5ba00db6333b1f8c924c1672bb..e46ee11504755285564b78964026e72da224aca0 100644
--- a/mo/web/menu.py
+++ b/mo/web/menu.py
@@ -27,7 +27,8 @@ def get_menu():
             MenuItem(url_for('org_index'), "Org"),
             MenuItem(url_for('org_place_root'), "Místa"),
             MenuItem(url_for('org_contest_root'), "Soutěž"),
-            MenuItem(url_for('org_users'), "Uživatelé"),
+            MenuItem(url_for('org_users'), "Soutěžící"),
+            MenuItem(url_for('org_users_orgs'), "Organizátoři"),
         ]
 
     # Login / user settings
diff --git a/mo/web/org.py b/mo/web/org.py
index a5bfa3cbcf707469197e0a640cc3a4d36356bd52..58f2ca2711e9b7966f3660d92fdbbb891b35f54c 100644
--- a/mo/web/org.py
+++ b/mo/web/org.py
@@ -378,11 +378,6 @@ def org_place_rights(id: int):
     )
 
 
-@app.route('/org/users/')
-def org_users():
-    return render_template('not_implemented.html')
-
-
 @app.route('/org/contest/')
 def org_contest_root():
     sess = db.get_session()
diff --git a/mo/web/org_users.py b/mo/web/org_users.py
new file mode 100644
index 0000000000000000000000000000000000000000..29b2cc20ebf948973bbc4117ab9ec5c7d6c92433
--- /dev/null
+++ b/mo/web/org_users.py
@@ -0,0 +1,166 @@
+from operator import or_
+from flask import render_template, redirect, url_for, flash, request
+from flask_wtf import FlaskForm
+import werkzeug.exceptions
+import wtforms
+
+from typing import Optional, List
+
+import mo
+import mo.db as db
+import mo.rights
+import mo.util
+from mo.web import app
+
+
+class PagerForm(FlaskForm):
+    limit = wtforms.IntegerField()
+    offset = wtforms.IntegerField()
+    next = wtforms.SubmitField("Další")
+    previous = wtforms.SubmitField("Předchozí")
+
+
+class UsersFilterForm(PagerForm):
+    # participants
+    year = wtforms.IntegerField("Ročník")
+    school_code = wtforms.StringField("Škola")
+
+    # rounds->participations
+    round_year = wtforms.IntegerField("Ročník")
+    round_category = wtforms.SelectField("Kategorie", choices=['*'] + sorted(db.get_categories()))
+    round_seq = wtforms.SelectField("Kolo", choices=['*'] + sorted(db.get_seqs()))
+    contest_site_code = wtforms.StringField("Soutěžní místo")
+    participation_state = wtforms.SelectField('Účast', choices=[('*', '*')] + list(db.PartState.choices()))
+
+    submit = wtforms.SubmitField("Filtrovat")
+
+
+@app.route('/org/users/')
+def org_users():
+    sess = db.get_session()
+
+    q = sess.query(db.User).filter_by(is_admin=False, is_org=False)
+    filter = UsersFilterForm(request.args)
+
+    filter_errors = []
+
+    participant_filter = sess.query(db.Participant.user_id)
+    participant_filter_apply = False
+    if filter.year.data:
+        participant_filter = participant_filter.filter_by(year=filter.year.data)
+        participant_filter_apply = True
+    print(filter.school_code.data)
+    if filter.school_code.data:
+        place = db.place_by_code(filter.school_code.data)
+        if place:
+            participant_filter = participant_filter.filter_by(school=place.place_id)
+            participant_filter_apply = True
+        else:
+            filter_errors.append("Neexistující kód školy")
+
+    if participant_filter_apply:
+        q = q.filter(db.User.user_id.in_(participant_filter))
+
+    round_filter = sess.query(db.Round.round_id)
+    round_filter_apply = False
+    if filter.round_year.data:
+        round_filter = round_filter.filter_by(year=filter.round_year.data)
+        round_filter_apply = True
+    if filter.round_category.data and filter.round_category.data != "*":
+        round_filter = round_filter.filter_by(category=filter.round_category.data)
+        round_filter_apply = True
+    if filter.round_seq.data and filter.round_seq.data != "*":
+        round_filter = round_filter.filter_by(seq=filter.round_seq.data)
+        round_filter_apply = True
+
+    contest_filter = sess.query(db.Contest.contest_id)
+    contest_filter_apply = False
+    if round_filter_apply:
+        contest_filter = contest_filter.filter(db.Contest.round_id.in_(round_filter))
+        contest_filter_apply = True
+    if filter.contest_site_code.data:
+        place = db.place_by_code(filter.contest_site_code.data)
+        if place:
+            contest_filter = contest_filter.filter_by(place_id=place.place_id)
+            contest_filter_apply = True
+        else:
+            filter_errors.append("Neexistující kód soutěžního místa")
+
+    participation_filter = sess.query(db.Participation.user_id)
+    participation_filter_apply = False
+    if contest_filter_apply:
+        participation_filter = participation_filter.filter(db.Participation.contest_id.in_(contest_filter))
+        participation_filter_apply = True
+    if filter.participation_state.data and filter.participation_state.data != '*':
+        participation_filter = participation_filter.filter_by(state=filter.participation_state.data)
+        participation_filter_apply = True
+
+    if participation_filter_apply:
+        q = q.filter(db.User.user_id.in_(participation_filter))
+
+    # print(str(q))
+    count = q.count()
+
+    if not filter.offset.data:
+        filter.offset.data = 0
+    if not filter.limit.data:
+        filter.limit.data = 50
+
+    if filter.previous.data:
+        filter.offset.data = max(0, filter.offset.data - 50)
+    if filter.next.data:
+        filter.offset.data = min(count // 50 * 50, filter.offset.data + 50)
+
+    q = q.offset(filter.offset.data)
+    q = q.limit(filter.limit.data)
+    users = q.all()
+
+    return render_template('org_users.html', users=users, count=count, filter=filter, filter_errors=filter_errors)
+
+
+class OrgsFilterForm(PagerForm):
+    # TODO: filtering by roles?
+    submit = wtforms.SubmitField("Filtrovat")
+
+
+@app.route('/org/users/orgs/')
+def org_users_orgs():
+    sess = db.get_session()
+
+    q = sess.query(db.User).filter(or_(db.User.is_admin, db.User.is_org))
+    filter = OrgsFilterForm(request.args)
+    # TODO: filtering by roles?
+
+    count = q.count()
+
+    if not filter.offset.data:
+        filter.offset.data = 0
+    if not filter.limit.data:
+        filter.limit.data = 50
+
+    if filter.previous.data:
+        filter.offset.data = max(0, filter.offset.data - 50)
+    if filter.next.data:
+        filter.offset.data = min(count // 50 * 50, filter.offset.data + 50)
+
+    q = q.offset(filter.offset.data)
+    q = q.limit(filter.limit.data)
+    users = q.all()
+
+    return render_template('org_users_orgs.html', users=users, count=count, filter=filter, filter_errors=None)
+
+
+@app.route('/org/user/<int:id>/')
+def org_user(id: int):
+    return render_template('not_implemented.html')
+
+
+@app.route('/org/user/<int:id>/edit')
+def org_user_edit(id: int):
+    return render_template('not_implemented.html')
+
+
+@app.route('/org/user/new/', defaults={'type': None})
+@app.route('/org/user/new/<type>/')
+def org_user_new(type: Optional[str]):
+    return render_template('not_implemented.html')
diff --git a/templates/org_users.html b/templates/org_users.html
new file mode 100644
index 0000000000000000000000000000000000000000..5710cb4af4218283e447345727b9977fb3c45ccb
--- /dev/null
+++ b/templates/org_users.html
@@ -0,0 +1,86 @@
+{% extends "base.html" %}
+{% import "bootstrap/wtf.html" as wtf %}
+{% block body %}
+<a class="pull-right btn btn-primary" href="{{ url_for('org_user_new') }}">Nový soutěžící</a>
+
+<h2>Soutěžící</h2>
+
+{% if filter_errors %}
+<div class="alert alert-danger" role="alert">
+	{{ filter_errors|join("<br>") }}
+</div>
+{% endif %}
+
+<form action="" method="GET" class="form" role="form">
+	<div class="row">
+		<div class='col-sm-2'><strong>Účast v kole:</strong></div>
+		<div class="form-group col-sm-2">
+			{{ wtf.form_field(filter.round_year) }}
+		</div>
+		<div class="form-group col-sm-2">
+			{{ wtf.form_field(filter.round_category) }}
+		</div>
+		<div class="form-group col-sm-2">
+			{{ wtf.form_field(filter.round_seq) }}
+		</div>
+		<div class="form-group col-sm-2">
+			{{ wtf.form_field(filter.contest_site_code, placeholder='Kód / #ID') }}
+		</div>
+		<div class="form-group col-sm-2">
+			{{ wtf.form_field(filter.participation_state) }}
+		</div>
+	</div>
+	<div class="row">
+		<div class='col-sm-2'><strong>Registrace:</strong></div>
+		<div class="form-group col-sm-2">
+			{{ wtf.form_field(filter.year) }}
+		</div>
+		<div class="form-group col-sm-2">
+			{{ wtf.form_field(filter.school_code, placeholder='Kód / #ID') }}
+		</div>
+		<div class="form-group col-sm-6 btn-group">
+			{{ wtf.form_field(filter.submit, class='btn btn-primary') }}
+			{% if filter.offset.data > 0 %}
+				{{ wtf.form_field(filter.previous) }}
+			{% else %}
+				<button class="btn" disabled>Předchozí</button>
+			{% endif %}
+			{% if count > filter.offset.data + filter.limit.data %}
+				{{ wtf.form_field(filter.next) }}
+			{% else %}
+				<button class="btn" disabled>Další</button>
+			{% endif %}
+
+			{% set max = filter.offset.data + filter.limit.data if filter.offset.data + filter.limit.data < count else count %}
+
+			<br><br>Zobrazuji záznamy <b>{{filter.offset.data + 1}}</b> až <b>{{ max }}</b> z <b>{{count}} nalezených soutěžících</b>.
+		</div>
+	</div>
+	<input type="hidden" name="offset" value="{{filter.offset.data}}">
+	<input type="hidden" name="limit" value="{{filter.limit.data}}">
+</form>
+
+{% if users %}
+<table class="table">
+	<thead>
+		<tr>
+			<th>Jméno</th><th>Příjmení</th><th>E-mail</th><th>Akce</th>
+		</tr>
+	</thead>
+{% for user in users %}
+	<tr>
+		<td>{{ user.first_name }}</td><td>{{ user.last_name }}</td>
+		<td><a href="mailto:{{ user.email }}">{{ user.email }}</a></td>
+		<td class='btn-group'>
+			<a class="btn btn-xs btn-default" href="{{ url_for('org_user', id=user.user_id) }}">Detail</a>
+			<a class="btn btn-xs btn-default" href="{{ url_for('org_user_edit', id=user.user_id) }}">Edit</a>
+		</td>
+	</tr>
+{% endfor %}
+</table>
+{% else %}
+Zadanému filtru nevyhovují žádní soutěžící.
+{% endif %}
+
+
+{% endblock %}
diff --git a/templates/org_users_orgs.html b/templates/org_users_orgs.html
new file mode 100644
index 0000000000000000000000000000000000000000..a7e54c460c0fc1cf96721af3079e641328847209
--- /dev/null
+++ b/templates/org_users_orgs.html
@@ -0,0 +1,60 @@
+{% extends "base.html" %}
+{% import "bootstrap/wtf.html" as wtf %}
+{% block body %}
+<a class="pull-right btn btn-primary" href="{{ url_for('org_user_new', type='org') }}">Nový organizátor</a>
+
+<h2>Organizátoři</h2>
+
+{% if filter_errors %}
+<div class="alert alert-danger" role="alert">
+	{{ filter_errors|join("<br>") }}
+</div>
+{% endif %}
+
+<form action="" method="GET" class="form" role="form">
+	<div class="row">
+		<div class="form-group col-sm-6 btn-group">
+			{% if filter.offset.data > 0 %}
+				{{ wtf.form_field(filter.previous) }}
+			{% else %}
+				<button class="btn" disabled>Předchozí</button>
+			{% endif %}
+			{% if count > filter.offset.data + filter.limit.data %}
+				{{ wtf.form_field(filter.next) }}
+			{% else %}
+				<button class="btn" disabled>Další</button>
+			{% endif %}
+
+			{% set max = filter.offset.data + filter.limit.data if filter.offset.data + filter.limit.data < count else count %}
+
+			<br><br>Zobrazuji záznamy <b>{{filter.offset.data + 1}}</b> až <b>{{ max }}</b> z <b>{{count}} nalezených organizátorů</b>.
+		</div>
+	</div>
+	<input type="hidden" name="offset" value="{{filter.offset.data}}">
+	<input type="hidden" name="limit" value="{{filter.limit.data}}">
+</form>
+
+{% if users %}
+<table class="table">
+	<thead>
+		<tr>
+			<th>Jméno</th><th>Příjmení</th><th>E-mail</th><th>Akce</th>
+		</tr>
+	</thead>
+{% for user in users %}
+	<tr>
+		<td>{{ user.first_name }}</td><td>{{ user.last_name }}</td>
+		<td><a href="mailto:{{ user.email }}">{{ user.email }}</a></td>
+		<td class='btn-group'>
+			<a class="btn btn-xs btn-default" href="{{ url_for('org_user', id=user.user_id) }}">Detail</a>
+			<a class="btn btn-xs btn-default" href="{{ url_for('org_user_edit', id=user.user_id) }}">Edit</a>
+		</td>
+	</tr>
+{% endfor %}
+</table>
+{% else %}
+Zadanému filtru nevyhovují žádní organizátoři.
+{% endif %}
+
+
+{% endblock %}