diff --git a/mo/rights.py b/mo/rights.py
index 1ab63fc07b9e4a2bd831c1f1567d74d84c9bac15..52ed4f316f086829780929fc6478b09bb17829bb 100644
--- a/mo/rights.py
+++ b/mo/rights.py
@@ -16,6 +16,8 @@ class Right(Enum):
     upload_solutions = auto()
     upload_feedback = auto()
     edit_points = auto()
+    edit_users = auto()
+    edit_orgs = auto()
 
 
 @dataclass
@@ -33,6 +35,8 @@ roles: List[Role] = [
             Right.assign_rights,
             Right.edit_place,
             Right.manage_contest,
+            Right.edit_users,
+            Right.edit_orgs,
         },
     ),
     Role(
@@ -42,6 +46,8 @@ roles: List[Role] = [
             Right.assign_rights,
             Right.edit_place,
             Right.manage_contest,
+            Right.edit_users,
+            Right.edit_orgs,
         },
     ),
     Role(
@@ -51,6 +57,7 @@ roles: List[Role] = [
             Right.assign_rights,
             Right.edit_place,
             Right.manage_contest,
+            Right.edit_users,
         },
     ),
     Role(
diff --git a/mo/web/org_users.py b/mo/web/org_users.py
index 29b2cc20ebf948973bbc4117ab9ec5c7d6c92433..885b630492ca5e2a3edcf94e43f8d0b66001d8a3 100644
--- a/mo/web/org_users.py
+++ b/mo/web/org_users.py
@@ -1,15 +1,19 @@
-from operator import or_
-from flask import render_template, redirect, url_for, flash, request
+from flask import render_template, g, redirect, url_for, flash, request
 from flask_wtf import FlaskForm
 import werkzeug.exceptions
 import wtforms
+from sqlalchemy import or_
+from sqlalchemy.orm import joinedload
 
 from typing import Optional, List
 
+from wtforms.validators import Email, Required
+
 import mo
 import mo.db as db
 import mo.rights
 import mo.util
+import mo.users
 from mo.web import app
 
 
@@ -38,6 +42,9 @@ class UsersFilterForm(PagerForm):
 @app.route('/org/users/')
 def org_users():
     sess = db.get_session()
+    rr = mo.rights.Rights(g.user)
+    rr.get_generic()
+    can_edit = rr.have_right(mo.rights.Right.edit_users)
 
     q = sess.query(db.User).filter_by(is_admin=False, is_org=False)
     filter = UsersFilterForm(request.args)
@@ -115,7 +122,10 @@ def org_users():
     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)
+    return render_template(
+        'org_users.html', users=users, count=count,
+        filter=filter, filter_errors=filter_errors, can_edit=can_edit
+    )
 
 
 class OrgsFilterForm(PagerForm):
@@ -126,6 +136,9 @@ class OrgsFilterForm(PagerForm):
 @app.route('/org/users/orgs/')
 def org_users_orgs():
     sess = db.get_session()
+    rr = mo.rights.Rights(g.user)
+    rr.get_generic()
+    can_edit = rr.have_right(mo.rights.Right.edit_orgs)
 
     q = sess.query(db.User).filter(or_(db.User.is_admin, db.User.is_org))
     filter = OrgsFilterForm(request.args)
@@ -147,20 +160,137 @@ def org_users_orgs():
     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)
+    return render_template(
+        'org_users_orgs.html', users=users, count=count,
+        filter=filter, filter_errors=None, can_edit=can_edit,
+    )
 
 
 @app.route('/org/user/<int:id>/')
 def org_user(id: int):
-    return render_template('not_implemented.html')
+    sess = db.get_session()
+    user = sess.query(db.User).get(id)
+    if not user:
+        raise werkzeug.exceptions.NotFound()
+
+    rr = mo.rights.Rights(g.user)
+    rr.get_generic()
+    if user.is_admin:
+        can_edit = False
+    elif user.is_org:
+        can_edit = rr.have_right(mo.rights.Right.edit_orgs)
+    else:
+        can_edit = rr.have_right(mo.rights.Right.edit_users)
+
+    participants = sess.query(db.Participant).filter_by(user_id=user.user_id)
+    rounds = sess.query(db.Participation).filter_by(user_id=user.user_id)
+
+    return render_template('org_user.html', user=user, can_edit=can_edit, participants=participants, rounds=rounds)
+
+
+class UserEditForm(FlaskForm):
+    first_name = wtforms.StringField("Jméno", validators=[Required()])
+    last_name = wtforms.StringField("Příjmení", validators=[Required()])
+    note = wtforms.TextAreaField("Poznámka")
+    submit = wtforms.SubmitField("Uložit")
+
 
+class NewUserForm(UserEditForm):
+    email = wtforms.StringField("E-mail", validators=[Required()])
+    submit = wtforms.SubmitField("Vytvořit")
 
-@app.route('/org/user/<int:id>/edit')
+
+@app.route('/org/user/<int:id>/edit', methods=("GET", "POST"))
 def org_user_edit(id: int):
-    return render_template('not_implemented.html')
+    sess = db.get_session()
+    user = mo.users.user_by_uid(id)
+    if not user:
+        raise werkzeug.exceptions.NotFound()
+
+    rr = mo.rights.Rights(g.user)
+    rr.get_generic()
+    if user.is_admin:
+        raise werkzeug.exceptions.Forbidden()
+    elif user.is_org and not rr.have_right(mo.rights.Right.edit_orgs):
+        raise werkzeug.exceptions.Forbidden()
+    elif not rr.have_right(mo.rights.Right.edit_users):
+        raise werkzeug.exceptions.Forbidden()
+
+    form = UserEditForm(obj=user)
+    if form.validate_on_submit():
+        form.populate_obj(user)
+
+        if sess.is_modified(user):
+            changes = db.get_object_changes(user)
+
+            app.logger.info(f"User {id} modified, changes: {changes}")
+            mo.util.log(
+                type=db.LogType.user,
+                what=id,
+                details={'action': 'edit', 'changes': changes},
+            )
+            sess.commit()
+            flash('Změny uživatele uloženy', 'success')
+        else:
+            flash(u'Žádné změny k uložení', 'info')
+
+        return redirect(url_for('org_user', id=id))
 
+    return render_template('org_user_edit.html', user=user, form=form)
 
-@app.route('/org/user/new/', defaults={'type': None})
-@app.route('/org/user/new/<type>/')
+
+@app.route('/org/user/new/', defaults={'type': None}, methods=('GET', 'POST'))
+@app.route('/org/user/new/<type>/', methods=('GET', 'POST'))
 def org_user_new(type: Optional[str]):
-    return render_template('not_implemented.html')
+    sess = db.get_session()
+    rr = mo.rights.Rights(g.user)
+    rr.get_generic()
+
+    if type is not None and type != "org":
+        raise werkzeug.exceptions.BadRequest()
+    if not rr.have_right(mo.rights.Right.edit_users):
+        raise werkzeug.exceptions.Forbidden()
+    if type == 'org' and not rr.have_right(mo.rights.Right.edit_orgs):
+        raise werkzeug.exceptions.Forbidden()
+
+    form = NewUserForm()
+    if form.validate_on_submit():
+        check = True
+
+        if mo.users.user_by_email(form.email.data) is not None:
+            flash('Účet s daným emailem již existuje', 'danger')
+            check = False
+
+        if check:
+            new_user = db.User()
+            form.populate_obj(new_user)
+            new_user.is_org = (type == 'org')
+            sess.add(new_user)
+            sess.flush()
+
+            app.logger.info(f"New user created: {db.row2dict(new_user)}")
+            mo.util.log(
+                type=db.LogType.user,
+                what=new_user.user_id,
+                details={'action': 'new', 'user': db.row2dict(new_user)},
+            )
+
+            sess.commit()
+            flash('Nový uživatel vytvořen', 'success')
+
+            # Send password (re)set link
+            token = mo.users.ask_reset_password(new_user)
+            link = url_for('reset', token=token, _external=True)
+            db.get_session().commit()
+
+            try:
+                mo.util.send_password_reset_email(new_user, link)
+                flash('Email s odkazem pro nastavení hesla odeslán na {}'.format(new_user.email), 'success')
+            except RuntimeError as e:
+                app.logger.error('Login: problém při posílání emailu: {}'.format(e))
+                flash('Problém při odesílání emailu s odkazem pro nastavení hesla', 'danger')
+
+            return redirect(url_for('org_user', id=new_user.user_id))
+
+    return render_template('org_user_new.html', form=form)
+
diff --git a/templates/org_user.html b/templates/org_user.html
new file mode 100644
index 0000000000000000000000000000000000000000..fa4d8892961a50a5d0159ac2796ae47894889b23
--- /dev/null
+++ b/templates/org_user.html
@@ -0,0 +1,88 @@
+{% extends "base.html" %}
+{% block body %}
+<h2>{% if user.is_org %}Organizátor:{% elif user.is_admin %}Správce:{% else %}Soutěžící:{% endif %} {{ user.first_name }} {{ user.last_name }}</h2>
+
+<table class=data>
+<tr><td>Jméno:</td><td>{{ user.first_name }}</td></tr>
+<tr><td>Příjmení:</td><td>{{ user.last_name }}</td></tr>
+<tr><td>E-mail:</td><td><a href="mailto:{{ user.email }}">{{ user.email }}</a></td></tr>
+{% if user.is_admin %}<tr><td>Administrátor:</td><td>ano</td></tr>{% endif %}
+{% if user.is_org %}<tr><td>Organizátor:</td><td>ano</td></tr>{% endif %}
+<tr><td>Poznámka:</td><td style="white-space: pre;">{{ user.note }}</td></tr>
+</table>
+
+{% if can_edit %}
+<div class="btn-group" role="group" style="margin: 10px 0px;">
+	<a class="btn btn-primary" href="{{ url_for('org_user_edit', id=user.user_id) }}">Editovat</a>
+</div>
+{% endif %}
+
+{% if user.is_org or user.is_admin %}
+<h3>Role</h3>
+
+<table class="table">
+	<thead>
+		<tr>
+			<th>Role</th><th>Ročník</th><th>Kategorie</th><th>Kolo</th><th>Oblast</th>
+		</tr>
+	</thead>
+{% for role in user.roles %}
+	<tr>
+		<td>{{ role.role.name }}</td>
+		<td>{{ role.year or '*' }}</td>
+		<td>{{ role.category or '*' }}</td>
+		<td>{{ role.seq or '*' }}</td>
+		<td>{{ role.place.type_name() + ": " + role.place.name or '*' }}</td>
+	</tr>
+{% endfor %}
+</table>
+{% endif %}
+
+<h3>Registrace v ročnících</h3>
+{% if participants.count() %}
+<table class="table">
+	<thead>
+		<tr>
+			<th>Ročník</th><th>Škola</th><th>Třída</th><th>Rok narození</th>
+		</tr>
+	</thead>
+{% for participant in participants %}
+	<tr>
+		<td>{{ participant.year }}</td>
+		<td><a href="{{ url_for('org_place', id=participant.school) }}">{{ participant.school_place.name }}</a></td>
+		<td>{{ participant.grade }}</td>
+		<td>{{ participant.birth_year }}</td>
+	</tr>
+{% endfor %}
+</table>
+{% else %}
+<p>Žádná registrace v ročníku</p>
+{% endif %}
+
+<h3>Účast v kolech</h3>
+{% if rounds.count() %}
+<table class="table">
+	<thead>
+		<tr>
+			<th>Ročník</th><th>Kategorie</th><th>Kolo</th><th>Místo</th><th>Stav účasti</th>
+		</tr>
+	</thead>
+{% for round in rounds %}
+	<tr>
+		<td>{{ round.contest.round.year }}</td>
+		<td>{{ round.contest.round.category }}</td>
+		<td>{{ round.contest.round.seq }}</td>
+		<td><a href="{{ url_for('org_place', id=round.contest.place_id) }}">{{ round.contest.place.name }}</a>
+			{% if round.place_id != round.contest.place_id %}
+				<br>(ale soutěží v <a href="{{ url_for('org_place', id=round.place_id) }}">{{ round.place.name }}</a>)
+			{% endif %}
+		</td>
+		<td>{{ round.state.name }}</td>
+	</tr>
+{% endfor %}
+</table>
+{% else %}
+<p>Žádná účast v kole</p>
+{% endif %}
+
+{% endblock %}
diff --git a/templates/org_user_edit.html b/templates/org_user_edit.html
new file mode 100644
index 0000000000000000000000000000000000000000..147c2e8cbd08732b16e065d66eb22aa80b9ef5a7
--- /dev/null
+++ b/templates/org_user_edit.html
@@ -0,0 +1,25 @@
+{% extends "base.html" %}
+{% import "bootstrap/wtf.html" as wtf %}
+{% block body %}
+<h2>{% if user.is_org %}Org:{% elif user.is_admin %}Admin:{% else %}Soutěžící{% endif %} {{ user.first_name }} {{ user.last_name }}</h2>
+
+<table class=data>
+<tr><td>Jméno:</td><td>{{ user.first_name }}</td></tr>
+<tr><td>Příjmení:</td><td>{{ user.last_name }}</td></tr>
+<tr><td>E-mail:</td><td><a href="mailto:{{ user.email }}">{{ user.email }}</a></td></tr>
+{% if user.is_admin %}<tr><td>Administrátor:</td><td>ano</td></tr>{% endif %}
+{% if user.is_org %}<tr><td>Organizátor:</td><td>ano</td></tr>{% endif %}
+<tr><td>Poznámka:</td><td style="white-space: pre;">{{ user.note }}</td></tr>
+</table>
+
+<a href='{{ url_for('org_user', id=user.user_id) }}'>Zpět na detail</a>
+
+<hr>
+
+<h3>Editace údajů</h3>
+
+<p>Email nelze editovat. Pro jeho změnu kontaktujte někoho ze správců.</p>
+
+{{ wtf.quick_form(form, form_type='horizontal') }}
+
+{% endblock %}
diff --git a/templates/org_user_new.html b/templates/org_user_new.html
new file mode 100644
index 0000000000000000000000000000000000000000..d3529c2b05a6c072b62d9357e7e557abe5bcb235
--- /dev/null
+++ b/templates/org_user_new.html
@@ -0,0 +1,10 @@
+{% extends "base.html" %}
+{% import "bootstrap/wtf.html" as wtf %}
+{% block body %}
+<h2>Nový {% if is_org %}organizátor{% else %}soutěžící{% endif %}</h2>
+
+<p>Na zadaný email dorazí email pro nastavení hesla. Email po vytvoření účtu již nelze měnit.</p>
+
+{{ wtf.quick_form(form, form_type='horizontal') }}
+
+{% endblock %}
diff --git a/templates/org_users_orgs.html b/templates/org_users_orgs.html
index a7e54c460c0fc1cf96721af3079e641328847209..97f2cf88985295fab127b2f12168024770322f7c 100644
--- a/templates/org_users_orgs.html
+++ b/templates/org_users_orgs.html
@@ -38,16 +38,19 @@
 <table class="table">
 	<thead>
 		<tr>
-			<th>Jméno</th><th>Příjmení</th><th>E-mail</th><th>Akce</th>
+			<th>Jméno</th><th>Příjmení</th><th>E-mail</th><th>Nejvyšší role</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>{% if user.is_admin %}administrátor{% else %}
+			{%- if user.roles|count > 0 %}{{user.roles[0].role.name}}{% else %}<i>žádná role</i>{% endif -%}
+		{% endif %}</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>
+			{% if can_edit and not user.is_admin %}<a class="btn btn-xs btn-default" href="{{ url_for('org_user_edit', id=user.user_id) }}">Edit</a>{% endif %}
 		</td>
 	</tr>
 {% endfor %}