Commit b0279054 authored by Robert Czechowski's avatar Robert Czechowski

Merge branch 'admin-page'

parents 1c827dbf 74721993
Pipeline #618 passed with stages
in 32 minutes and 8 seconds
......@@ -48,12 +48,12 @@ type MedalValueResult = MedalResult<MedalValue>;
fn fill_user_data(session: &SessionUser, data: &mut json_val::Map<String, serde_json::Value>) {
if session.is_logged_in() {
data.insert("logged_in".to_string(), to_json(&true));
data.insert("username".to_string(), to_json(&session.username));
data.insert("firstname".to_string(), to_json(&session.firstname));
data.insert("lastname".to_string(), to_json(&session.lastname));
data.insert("teacher".to_string(), to_json(&session.is_teacher));
data.insert("csrf_token".to_string(), to_json(&session.csrf_token));
}
data.insert("username".to_string(), to_json(&session.username));
data.insert("firstname".to_string(), to_json(&session.firstname));
data.insert("lastname".to_string(), to_json(&session.lastname));
data.insert("teacher".to_string(), to_json(&session.is_teacher));
data.insert("csrf_token".to_string(), to_json(&session.csrf_token));
data.insert("parent".to_string(), to_json(&"base"));
}
......@@ -1030,6 +1030,141 @@ pub fn edit_profile<T: MedalConnection>(conn: &T, session_token: &str, user_id:
Ok(result)
}
pub fn admin_index<T: MedalConnection>(conn: &T, session_token: &str) -> MedalValueResult {
let session = conn.get_session(&session_token).ensure_logged_in().ok_or(MedalError::NotLoggedIn)?;
if session.id != 1 {
return Err(MedalError::AccessDenied);
}
let data = json_val::Map::new();
Ok(("admin".to_string(), data))
}
pub fn admin_search_users<T: MedalConnection>(conn: &T, session_token: &str,
s_data: (Option<i32>,
Option<String>,
Option<String>,
Option<String>,
Option<String>,
Option<String>))
-> MedalValueResult
{
let session = conn.get_session(&session_token).ensure_logged_in().ok_or(MedalError::NotLoggedIn)?;
if session.id != 1 {
return Err(MedalError::AccessDenied);
}
let mut data = json_val::Map::new();
match conn.get_search_users(s_data) {
Ok(users) => data.insert("users".to_string(), to_json(&users)),
Err(groups) => data.insert("groups".to_string(), to_json(&groups)),
};
Ok(("admin_search_results".to_string(), data))
}
pub fn admin_show_user<T: MedalConnection>(conn: &T, user_id: i32, session_token: &str) -> MedalValueResult {
let session = conn.get_session(&session_token).ensure_logged_in().ok_or(MedalError::NotLoggedIn)?;
if session.id != 1 {
return Err(MedalError::AccessDenied);
}
let mut data = json_val::Map::new();
let (user, opt_group) = conn.get_user_and_group_by_id(user_id).ok_or(MedalError::AccessDenied)?;
fill_user_data(&user, &mut data);
data.insert("logincode".to_string(), to_json(&user.logincode));
data.insert("userid".to_string(), to_json(&user.id));
data.insert("oauthid".to_string(), to_json(&user.oauth_foreign_id));
data.insert("oauthprovider".to_string(), to_json(&user.oauth_provider));
if let Some(group) = opt_group {
data.insert("group_id".to_string(), to_json(&group.id));
data.insert("group_name".to_string(), to_json(&group.name));
}
let v: Vec<GroupInfo> =
conn.get_groups(user_id)
.iter()
.map(|g| GroupInfo { id: g.id.unwrap(),
name: g.name.clone(),
tag: g.tag.clone(),
code: g.groupcode.clone() })
.collect();
data.insert("group".to_string(), to_json(&v));
data.insert("csrf_token".to_string(), to_json(&session.csrf_token));
Ok(("admin_user".to_string(), data))
}
#[allow(unused_variables)]
pub fn admin_delete_user<T: MedalConnection>(conn: &T, user_id: i32, session_token: &str, csrf_token: &str)
-> MedalValueResult {
let data = json_val::Map::new();
Ok(("profile".to_string(), data))
}
pub fn admin_show_group<T: MedalConnection>(conn: &T, group_id: i32, session_token: &str) -> MedalValueResult {
let session = conn.get_session(&session_token).ensure_logged_in().ok_or(MedalError::NotLoggedIn)?;
if session.id != 1 {
return Err(MedalError::AccessDenied);
}
let group = conn.get_group_complete(group_id).unwrap(); // TODO handle error
let mut data = json_val::Map::new();
let gi = GroupInfo { id: group.id.unwrap(),
name: group.name.clone(),
tag: group.tag.clone(),
code: group.groupcode.clone() };
let v: Vec<MemberInfo> =
group.members
.iter()
.map(|m| MemberInfo { id: m.id,
firstname: m.firstname.clone().unwrap_or_else(|| "".to_string()),
lastname: m.lastname.clone().unwrap_or_else(|| "".to_string()),
grade: grade_to_string(m.grade),
logincode: m.logincode.clone().unwrap_or_else(|| "".to_string()) })
.collect();
data.insert("group".to_string(), to_json(&gi));
data.insert("member".to_string(), to_json(&v));
data.insert("groupname".to_string(), to_json(&gi.name));
data.insert("group_admin_id".to_string(), to_json(&group.admin));
let user = conn.get_user_by_id(group.admin).ok_or(MedalError::AccessDenied)?;
data.insert("group_admin_firstname".to_string(), to_json(&user.firstname));
data.insert("group_admin_lastname".to_string(), to_json(&user.lastname));
Ok(("admin_group".to_string(), data))
}
#[allow(unused_variables)]
pub fn admin_delete_group<T: MedalConnection>(conn: &T, group_id: i32, session_token: &str, csrf_token: &str)
-> MedalValueResult {
let data = json_val::Map::new();
Ok(("profile".to_string(), data))
}
#[allow(unused_variables)]
pub fn admin_show_participation<T: MedalConnection>(conn: &T, participation_id: i32, session_token: &str)
-> MedalValueResult {
let data = json_val::Map::new();
Ok(("profile".to_string(), data))
}
#[allow(unused_variables)]
pub fn admin_delete_participation<T: MedalConnection>(conn: &T, participation_id: i32, session_token: &str,
csrf_token: &str)
-> MedalValueResult
{
let data = json_val::Map::new();
Ok(("profile".to_string(), data))
}
#[derive(PartialEq)]
pub enum UserType {
User,
......
......@@ -1082,6 +1082,56 @@ impl MedalConnection for Connection {
.unwrap();
Some(group)
}
fn get_search_users(&self,
(s_id, s_firstname, s_lastname, s_logincode, s_groupcode, s_pms_id): (Option<i32>,
Option<String>,
Option<String>,
Option<String>,
Option<String>,
Option<String>))
-> Result<Vec<(i32, String, String)>, Vec<(i32, String, String)>>
{
if let Some(id) = s_id {
let query = "SELECT id, firstname, lastname
FROM session
WHERE id = $1
LIMIT 30";
Ok(self.query_map_many(query, &[&id], |row| (row.get(0), row.get(1), row.get(2))).unwrap())
} else if let Some(logincode) = s_logincode {
let query = "SELECT id, firstname, lastname
FROM session
WHERE logincode = $1
LIMIT 30";
Ok(self.query_map_many(query, &[&logincode], |row| (row.get(0), row.get(1), row.get(2))).unwrap())
} else if let Some(groupcode) = s_groupcode {
let query = "SELECT id, name, tag
FROM usergroup
WHERE groupcode = $1
LIMIT 30";
Err(self.query_map_many(query, &[&groupcode], |row| {
(row.get(0),
format!("Gruppe: {}", row.get::<_, String>(1)),
format!("(Marker: {})", row.get::<_, String>(2)))
})
.unwrap())
} else if let Some(pms_id) = s_pms_id {
let query = "SELECT id, firstname, lastname
FROM session
WHERE oauth_foreign_id = $1
LIMIT 30";
Ok(self.query_map_many(query, &[&pms_id], |row| (row.get(0), row.get(1), row.get(2))).unwrap())
} else if let (Some(firstname), Some(lastname)) = (s_firstname, s_lastname) {
let query = "SELECT id, firstname, lastname
FROM session
WHERE firstname LIKE $1
AND lastname LIKE $2
LIMIT 30";
Ok(self.query_map_many(query, &[&firstname, &lastname], |row| (row.get(0), row.get(1), row.get(2)))
.unwrap())
} else {
Ok(Vec::new())
}
}
fn get_debug_information(&self) -> String {
let duration = Duration::minutes(60);
......
......@@ -50,6 +50,15 @@ pub trait MedalConnection {
fn get_groups_complete(&self, session_id: i32) -> Vec<Group>;
fn get_group_complete(&self, group_id: i32) -> Option<Group>;
fn get_search_users(&self,
_: (Option<i32>,
Option<String>,
Option<String>,
Option<String>,
Option<String>,
Option<String>))
-> Result<Vec<(i32, String, String)>, Vec<(i32, String, String)>>;
fn get_debug_information(&self) -> String;
fn reset_all_contest_visibilities(&self);
......
......@@ -1177,6 +1177,56 @@ impl MedalConnection for Connection {
.unwrap();
Some(group)
}
fn get_search_users(&self,
(s_id, s_firstname, s_lastname, s_logincode, s_groupcode, s_pms_id): (Option<i32>,
Option<String>,
Option<String>,
Option<String>,
Option<String>,
Option<String>))
-> Result<Vec<(i32, String, String)>, Vec<(i32, String, String)>>
{
if let Some(id) = s_id {
let query = "SELECT id, firstname, lastname
FROM session
WHERE id = $1
LIMIT 30";
Ok(self.query_map_many(query, &[&id], |row| (row.get(0), row.get(1), row.get(2))).unwrap())
} else if let Some(logincode) = s_logincode {
let query = "SELECT id, firstname, lastname
FROM session
WHERE logincode = $1
LIMIT 30";
Ok(self.query_map_many(query, &[&logincode], |row| (row.get(0), row.get(1), row.get(2))).unwrap())
} else if let Some(groupcode) = s_groupcode {
let query = "SELECT id, name, tag
FROM usergroup
WHERE groupcode = $1
LIMIT 30";
Err(self.query_map_many(query, &[&groupcode], |row| {
(row.get(0),
format!("Gruppe: {}", row.get::<_, String>(1)),
format!("(Marker: {})", row.get::<_, String>(2)))
})
.unwrap())
} else if let Some(pms_id) = s_pms_id {
let query = "SELECT id, firstname, lastname
FROM session
WHERE oauth_foreign_id = $1
LIMIT 30";
Ok(self.query_map_many(query, &[&pms_id], |row| (row.get(0), row.get(1), row.get(2))).unwrap())
} else if let (Some(firstname), Some(lastname)) = (s_firstname, s_lastname) {
let query = "SELECT id, firstname, lastname
FROM session
WHERE firstname LIKE $1
AND lastname LIKE $2
LIMIT 30";
Ok(self.query_map_many(query, &[&firstname, &lastname], |row| (row.get(0), row.get(1), row.get(2)))
.unwrap())
} else {
Ok(Vec::new())
}
}
fn get_debug_information(&self) -> String {
let duration = Duration::minutes(60);
......
......@@ -1177,6 +1177,56 @@ impl MedalConnection for Connection {
.unwrap();
Some(group)
}
fn get_search_users(&self,
(s_id, s_firstname, s_lastname, s_logincode, s_groupcode, s_pms_id): (Option<i32>,
Option<String>,
Option<String>,
Option<String>,
Option<String>,
Option<String>))
-> Result<Vec<(i32, String, String)>, Vec<(i32, String, String)>>
{
if let Some(id) = s_id {
let query = "SELECT id, firstname, lastname
FROM session
WHERE id = ?1
LIMIT 30";
Ok(self.query_map_many(query, &[&id], |row| (row.get(0), row.get(1), row.get(2))).unwrap())
} else if let Some(logincode) = s_logincode {
let query = "SELECT id, firstname, lastname
FROM session
WHERE logincode = ?1
LIMIT 30";
Ok(self.query_map_many(query, &[&logincode], |row| (row.get(0), row.get(1), row.get(2))).unwrap())
} else if let Some(groupcode) = s_groupcode {
let query = "SELECT id, name, tag
FROM usergroup
WHERE groupcode = ?1
LIMIT 30";
Err(self.query_map_many(query, &[&groupcode], |row| {
(row.get(0),
format!("Gruppe: {}", row.get::<_, String>(1)),
format!("(Marker: {})", row.get::<_, String>(2)))
})
.unwrap())
} else if let Some(pms_id) = s_pms_id {
let query = "SELECT id, firstname, lastname
FROM session
WHERE oauth_foreign_id = ?1
LIMIT 30";
Ok(self.query_map_many(query, &[&pms_id], |row| (row.get(0), row.get(1), row.get(2))).unwrap())
} else if let (Some(firstname), Some(lastname)) = (s_firstname, s_lastname) {
let query = "SELECT id, firstname, lastname
FROM session
WHERE firstname LIKE ?1
AND lastname LIKE ?2
LIMIT 30";
Ok(self.query_map_many(query, &[&firstname, &lastname], |row| (row.get(0), row.get(1), row.get(2)))
.unwrap())
} else {
Ok(Vec::new())
}
}
fn get_debug_information(&self) -> String {
let duration = Duration::minutes(60);
......
......@@ -871,6 +871,109 @@ fn user_post<C>(req: &mut Request) -> IronResult<Response>
//old: Ok(Response::with((status::Found, Redirect(url_for!(req, "user", "userid" => format!("{}",user_id))))))
}
fn admin<C>(req: &mut Request) -> IronResult<Response>
where C: MedalConnection + std::marker::Send + 'static {
let session_token = req.expect_session_token()?;
let (template, data) = with_conn![core::admin_index, C, req, &session_token].aug(req)?;
let mut resp = Response::new();
resp.set_mut(Template::new(&template, data)).set_mut(status::Ok);
Ok(resp)
}
fn admin_users<C>(req: &mut Request) -> IronResult<Response>
where C: MedalConnection + std::marker::Send + 'static {
let session_token = req.expect_session_token()?;
let (s_id, s_firstname, s_lastname, s_logincode, s_groupcode, s_pms_id) = {
let formdata = itry!(req.get_ref::<UrlEncodedBody>());
(formdata.get("id").map(|x| x[0].parse::<i32>().unwrap_or(0)),
formdata.get("firstname").map(|x| x[0].to_owned()),
formdata.get("lastname").map(|x| x[0].to_owned()),
formdata.get("logincode").map(|x| x[0].to_owned()),
formdata.get("groupcode").map(|x| x[0].to_owned()),
formdata.get("pmsid").map(|x| x[0].to_owned()))
};
let (template, data) = with_conn![core::admin_search_users,
C,
req,
&session_token,
(s_id, s_firstname, s_lastname, s_logincode, s_groupcode, s_pms_id)].aug(req)?;
let mut resp = Response::new();
resp.set_mut(Template::new(&template, data)).set_mut(status::Ok);
Ok(resp)
}
fn admin_user<C>(req: &mut Request) -> IronResult<Response>
where C: MedalConnection + std::marker::Send + 'static {
let user_id = req.expect_int::<i32>("userid")?;
let session_token = req.expect_session_token()?;
let csrf_token = if let Ok(formdata) = req.get_ref::<UrlEncodedBody>() {
// or iexpect!(formdata.get("csrf_token"))[0].to_owned(), ?
formdata.get("csrf_token").map(|x| x[0].to_owned())
} else {
None
};
let (template, data) = if let Some(csrf_token) = csrf_token {
with_conn![core::admin_delete_user, C, req, user_id, &session_token, &csrf_token].aug(req)?
} else {
with_conn![core::admin_show_user, C, req, user_id, &session_token].aug(req)?
};
let mut resp = Response::new();
resp.set_mut(Template::new(&template, data)).set_mut(status::Ok);
Ok(resp)
}
fn admin_group<C>(req: &mut Request) -> IronResult<Response>
where C: MedalConnection + std::marker::Send + 'static {
let group_id = req.expect_int::<i32>("groupid")?;
let session_token = req.expect_session_token()?;
let csrf_token = if let Ok(formdata) = req.get_ref::<UrlEncodedBody>() {
formdata.get("csrf_token").map(|x| x[0].to_owned())
} else {
None
};
let (template, data) = if let Some(csrf_token) = csrf_token {
with_conn![core::admin_delete_group, C, req, group_id, &session_token, &csrf_token].aug(req)?
} else {
with_conn![core::admin_show_group, C, req, group_id, &session_token].aug(req)?
};
let mut resp = Response::new();
resp.set_mut(Template::new(&template, data)).set_mut(status::Ok);
Ok(resp)
}
fn admin_participation<C>(req: &mut Request) -> IronResult<Response>
where C: MedalConnection + std::marker::Send + 'static {
let group_id = req.expect_int::<i32>("participationid")?;
let session_token = req.expect_session_token()?;
let csrf_token = if let Ok(formdata) = req.get_ref::<UrlEncodedBody>() {
formdata.get("csrf_token").map(|x| x[0].to_owned())
} else {
None
};
let (template, data) = if let Some(csrf_token) = csrf_token {
with_conn![core::admin_delete_participation, C, req, group_id, &session_token, &csrf_token].aug(req)?
} else {
with_conn![core::admin_show_participation, C, req, group_id, &session_token].aug(req)?
};
let mut resp = Response::new();
resp.set_mut(Template::new(&template, data)).set_mut(status::Ok);
Ok(resp)
}
#[derive(Deserialize, Debug)]
struct OAuthAccess {
access_token: String,
......@@ -1097,6 +1200,14 @@ pub fn start_server<C>(conn: C, config: Config) -> iron::error::HttpResult<iron:
user: get "/user/:userid" => user::<C>,
user_post: post "/user/:userid" => user_post::<C>,
task: get "/task/:taskid" => task::<C>,
admin: get "/admin" => admin::<C>,
admin_users: post "/admin/user/" => admin_users::<C>,
admin_user: get "/admin/user/:userid" => admin_user::<C>,
admin_user_post: post "/admin/user/:userid" => admin_user::<C>,
admin_group: get "/admin/group/:groupid" => admin_group::<C>,
admin_group_post: post "/admin/group/:groupid" => admin_group::<C>,
admin_participation: get "/admin/participation/:participationid" => admin_participation::<C>,
admin_participation_post: post "/admin/participation/:participationid" => admin_participation::<C>,
oauth: get "/oauth/:oauthid" => oauth::<C>,
check_cookie: get "/cookie" => cookie_warning,
dbstatus: get "/dbstatus" => dbstatus::<C>,
......
<h1>Admin-Suche</h1>
<p>Suche beachtet Groß-/Kleinschreibung. Das Prozentzeichen % ist ein Wildcart in der Namenssuche. Die Suche gibt nur bis zu 30 Ergebnisse aus, auch wenn es mehr gibt!</p>
<p>
<form action="/admin/user/" method="post">
Vorname:<br>
<input type="text" name="firstname">
<br>
Nachname:<br>
<input type="text" name="lastname" autofocus>
<br><br>
<input type="submit" value="search">
</form>
</p>
<p>
<form action="/admin/user/" method="post">
Logincode:<br>
<input type="text" name="logincode">
<br><br>
<input type="submit" value="search">
</form>
</p>
<p>
<form action="/admin/user/" method="post">
Gruppencode:<br>
<input type="text" name="groupcode">
<br><br>
<input type="submit" value="search">
</form>
</p>
<p>
<form action="/admin/user/" method="post">
ID:<br>
<input type="text" name="id">
<br><br>
<input type="submit" value="search">
</form>
</p>
<p>
<form action="/admin/user/" method="post">
PMS-ID:<br>
<input type="text" name="pmsid">
<br><br>
<input type="submit" value="search">
</form>
</p>
<h1>Gruppe: {{group.name}} ({{group.id}})</h1>
<p>
Id: {{group.id}}<br>
Name: {{group.name}}<br>
Gruppencode: {{group.code}}<br>
Marker: {{group.tag}}
</p>
<p>Gruppen-Administrator: <a href="/admin/user/{{group_admin_id}}">{{group_admin_firstname}} {{group_admin_lastname}} ({{group_admin_id}})</a></p>
<h2>Mitglieder</h2>
<table>
<tr>
<th>Id</th>
<th>Name</th>
<th>Logincode</th>
<th>Jahrgangstufe</th>
</tr>
{{#each member}}
<tr>
<td><a href="/admin/user/{{id}}">{{id}}:</a></td>
<td><a href="/admin/user/{{id}}">{{firstname}} {{lastname}}</a></td>
<td>{{logincode}}</td>
<td>{{grade}}</td>
</tr>
{{/each}}
</table>
<h1>Ergebnisse</h1>
{{#if users}}
<h2>Benutzer</h2>
<ul>
{{#each users}}
<li><a href="{{this.0}}">{{this.0}}: {{this.1}} {{this.2}}</li>
{{/each}}
</ul>
{{/if}}
{{#if groups}}
<h2>Gruppen</h2>
<ul>
{{#each groups}}
<li><a href="/admin/group/{{this.0}}">{{this.0}}: {{this.1}} {{this.2}}</li>
{{/each}}
</ul>
{{/if}}
<h1>Benutzer {{firstname}} {{lastname}} ({{userid}})</h1>
Id: {{userid}}<br>
Vorname: {{firstname}}<br>
Nachname: {{lastname}}<br>
{{#if username}}Benutzername: {{username}}<br>{{/if}}
{{#if logincode}}Logincode: {{logincode}}<br>{{/if}}
{{#if oauthid}}OAuth-Login: {{oauthprovider}} ({{oauthprovider}}-id: {{oauthid}})<br>{{/if}}
{{#if teacher}}Ist Lehrer <br>{{/if}}
{{#if logged_id}}Ist eingeloggt <br>{{/if}}
<h2>Gruppen</h2>
{{#if group}}
<h3>Admin von</h3>
<table>
<tr>
<th>Id</th>
<th>Name</th>
<th>Gruppencode</th>
<th>Marker</th>
</tr>
{{#each group}}
<tr>
<td><a href="/admin/group/{{id}}">{{id}}:</a></td>
<td><a href="/admin/group/{{id}}">{{name}}</a></td>
<td>{{code}}</td>
<td>{{tag}}</td>
</tr>
{{/each}}