mirror of https://github.com/EasyCTF/librectf
more frontend
This commit is contained in:
parent
29fd690ad7
commit
95c71b68b2
|
@ -281,6 +281,20 @@ impl UsefulFunctions<sqlite::Sqlite> for sqlite::SqlitePooledConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DbConn {
|
impl DbConn {
|
||||||
|
/// Tries to fetch the user with the given id.
|
||||||
|
pub fn fetch_user_id(&self, id: i32) -> Result<User, Error> {
|
||||||
|
use crate::schema::users::dsl;
|
||||||
|
let query = dsl::users.filter(dsl::id.eq(id));
|
||||||
|
match self {
|
||||||
|
#[cfg(feature = "mysql")]
|
||||||
|
DbConn::Mysql(conn) => query.first(conn),
|
||||||
|
#[cfg(feature = "postgres")]
|
||||||
|
DbConn::Postgres(conn) => query.first(conn),
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
|
DbConn::Sqlite(conn) => query.first(conn),
|
||||||
|
}
|
||||||
|
.map_err(Error::from)
|
||||||
|
}
|
||||||
/// Tries to fetch the user with the given email. (TODO: lookup by username)
|
/// Tries to fetch the user with the given email. (TODO: lookup by username)
|
||||||
pub fn fetch_user(&self, email: impl AsRef<str>) -> Result<User, Error> {
|
pub fn fetch_user(&self, email: impl AsRef<str>) -> Result<User, Error> {
|
||||||
use crate::schema::users::dsl;
|
use crate::schema::users::dsl;
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
use tera::Context;
|
|
||||||
use warp::Filter;
|
use warp::Filter;
|
||||||
|
|
||||||
|
use crate::extractors::{get_context, navbar, Context};
|
||||||
use crate::render::render_template;
|
use crate::render::render_template;
|
||||||
|
|
||||||
pub fn get_index() -> Resp!() {
|
pub fn get_index() -> Resp!() {
|
||||||
warp::path::end().and_then(|| render_template("base/index.html", Context::new()))
|
warp::path::end()
|
||||||
|
.and(navbar())
|
||||||
|
.and(get_context())
|
||||||
|
.and_then(|ctx: Context| render_template("base/index.html", ctx.into()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,60 @@
|
||||||
use core::State;
|
use core::{Error, State};
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use tera::Context as TeraContext;
|
||||||
use warp::{Filter, Rejection};
|
use warp::{Filter, Rejection};
|
||||||
|
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct Context(::tera::Context);
|
pub struct Context(pub TeraContext);
|
||||||
|
|
||||||
fn get_context() -> impl Clone + Filter<Extract = (Context,), Error = Rejection> {
|
impl Deref for Context {
|
||||||
warp::ext::get::<State>()
|
type Target = TeraContext;
|
||||||
.and(warp::ext::get::<Session>())
|
fn deref(&self) -> &Self::Target {
|
||||||
.map(|state, session| Context::default())
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for Context {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<TeraContext> for Context {
|
||||||
|
fn into(self) -> TeraContext {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_context() -> impl Clone + Filter<Extract = (Context,), Error = Rejection> {
|
||||||
|
warp::ext::get::<Context>()
|
||||||
.or(warp::any().map(|| Context::default()))
|
.or(warp::any().map(|| Context::default()))
|
||||||
.unify()
|
.unify()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_navbar(state: &State, session: &Session, ctx: &mut Context) -> Result<(), Error> {
|
||||||
|
let conn = state.get_connection()?;
|
||||||
|
|
||||||
|
// retrieve the user data
|
||||||
|
if let Some(user_id) = session.user_id {
|
||||||
|
conn.fetch_user_id(user_id)
|
||||||
|
.map(|user| ctx.insert("user", &user))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Generates all of the information needed to populate the navbar.
|
/// Generates all of the information needed to populate the navbar.
|
||||||
pub fn navbar() -> impl Clone + Filter<Extract = (), Error = Rejection> {
|
pub fn navbar() -> impl Clone + Filter<Extract = (), Error = Rejection> {
|
||||||
get_context().map(|ctx| {}).untuple_one()
|
warp::ext::get::<State>()
|
||||||
|
.and(warp::ext::get::<Session>())
|
||||||
|
.and(get_context())
|
||||||
|
.map(|state: State, session: Session, mut ctx: Context| {
|
||||||
|
render_navbar(&state, &session, &mut ctx).unwrap_or_else(|err| {
|
||||||
|
println!("err: {:?}", err);
|
||||||
|
});
|
||||||
|
warp::ext::set::<Context>(ctx);
|
||||||
|
})
|
||||||
|
.untuple_one()
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ use warp::{Filter, Rejection};
|
||||||
#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)]
|
||||||
pub struct Session {
|
pub struct Session {
|
||||||
pub user_id: Option<i32>,
|
pub user_id: Option<i32>,
|
||||||
|
pub team_id: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract() -> impl Clone + Filter<Extract = (), Error = Rejection> {
|
pub fn extract() -> impl Clone + Filter<Extract = (), Error = Rejection> {
|
||||||
|
@ -48,8 +49,9 @@ pub fn apply() -> impl Clone + Filter<Extract = (Option<String>,), Error = Rejec
|
||||||
.map(|data| {
|
.map(|data| {
|
||||||
jar.private(&key).add(
|
jar.private(&key).add(
|
||||||
Cookie::build("session", data)
|
Cookie::build("session", data)
|
||||||
.secure(true)
|
// .secure(true) // TODO: enable this based on a config
|
||||||
.http_only(true)
|
.http_only(true)
|
||||||
|
.path("/")
|
||||||
.same_site(SameSite::Strict)
|
.same_site(SameSite::Strict)
|
||||||
.finish(),
|
.finish(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,16 +4,18 @@ use core::{
|
||||||
Error, State,
|
Error, State,
|
||||||
};
|
};
|
||||||
use http::uri::Uri;
|
use http::uri::Uri;
|
||||||
use tera::Context;
|
|
||||||
use warp::Filter;
|
use warp::Filter;
|
||||||
use wtforms::Form;
|
use wtforms::Form;
|
||||||
|
|
||||||
use crate::extractors::navbar;
|
use crate::extractors::{get_context, navbar, Context};
|
||||||
use crate::render::render_template;
|
use crate::render::render_template;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
|
||||||
pub fn get_login() -> Resp!() {
|
pub fn get_login() -> Resp!() {
|
||||||
navbar().and_then(|| render_template("users/login.html", Context::new()))
|
warp::path::end()
|
||||||
|
.and(navbar())
|
||||||
|
.and(get_context())
|
||||||
|
.and_then(|ctx: Context| render_template("users/login.html", ctx.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn post_login() -> Resp!() {
|
pub fn post_login() -> Resp!() {
|
||||||
|
@ -39,11 +41,17 @@ pub fn post_login() -> Resp!() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_profile() -> Resp!() {
|
pub fn get_profile() -> Resp!() {
|
||||||
navbar().and_then(|| render_template("users/profile.html", Context::new()))
|
warp::path::end()
|
||||||
|
.and(navbar())
|
||||||
|
.and(get_context())
|
||||||
|
.and_then(|ctx: Context| render_template("users/profile.html", ctx.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_register() -> Resp!() {
|
pub fn get_register() -> Resp!() {
|
||||||
navbar().and_then(|| render_template("users/register.html", Context::new()))
|
warp::path::end()
|
||||||
|
.and(navbar())
|
||||||
|
.and(get_context())
|
||||||
|
.and_then(|ctx: Context| render_template("users/register.html", ctx.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn post_register() -> Resp!() {
|
pub fn post_register() -> Resp!() {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
<title>{% block title %}{% endblock %} - LibreCTF</title>
|
<title>{% block title %}{% endblock %} - LibreCTF</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="container navbar" role="navigation" aria-label="main navigation">
|
<nav class="container navbar" style="margin-bottom: 20px;" role="navigation" aria-label="main navigation">
|
||||||
<div class="navbar-brand">
|
<div class="navbar-brand">
|
||||||
<a class="navbar-item" href="/"><h3>LibreCTF</h3></a>
|
<a class="navbar-item" href="/"><h3>LibreCTF</h3></a>
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
<div id="navbarBasicExample" class="navbar-menu">
|
<div id="navbarBasicExample" class="navbar-menu">
|
||||||
<div class="navbar-start">
|
<div class="navbar-start">
|
||||||
<a class="navbar-item">Home</a>
|
<a class="navbar-item" href="/">Home</a>
|
||||||
<a class="navbar-item">Documentation</a>
|
<a class="navbar-item">Documentation</a>
|
||||||
|
|
||||||
<div class="navbar-item has-dropdown is-hoverable">
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
|
@ -39,10 +39,22 @@
|
||||||
|
|
||||||
<div class="navbar-end">
|
<div class="navbar-end">
|
||||||
<div class="navbar-item">
|
<div class="navbar-item">
|
||||||
<div class="buttons">
|
{% if user %}
|
||||||
<a href="/users/register" class="button is-primary"><strong>Sign up</strong></a>
|
<a class="navbar-item">My Team</a>
|
||||||
<a href="/users/login" class="button is-light">Log in</a>
|
<div class="navbar-item has-dropdown is-hoverable">
|
||||||
</div>
|
<a class="navbar-link">{{ user.name }}</a>
|
||||||
|
<div class="navbar-dropdown">
|
||||||
|
<a class="navbar-item" href="/users/profile">Profile</a>
|
||||||
|
<hr class="navbar-divider">
|
||||||
|
<a class="navbar-item" href="/users/logout">Logout</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="/users/register" class="button is-primary"><strong>Sign up</strong></a>
|
||||||
|
<a href="/users/login" class="button is-light">Log in</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,32 @@
|
||||||
{% extends "layout.html" %}
|
{% extends "layout.html" %}
|
||||||
{% block title %}Register{% endblock %}
|
{% block title %}Profile{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<section class="container">
|
||||||
|
<div class="columns">
|
||||||
|
<div class="column is-one-quarter">
|
||||||
|
<nav class="panel">
|
||||||
|
<div class="panel-block">
|
||||||
|
<p class="control has-icons-left">
|
||||||
|
<input class="input" type="text" placeholder="search">
|
||||||
|
<span class="icon is-left">
|
||||||
|
<i class="fas fa-search" aria-hidden="true"></i>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<div class="column">
|
||||||
|
<a href="/users/settings" class="button is-link" style="float: right; margin-right: 30px;">Settings</a>
|
||||||
|
<div class="tabs is-boxed">
|
||||||
|
<ul>
|
||||||
|
<li class="is-active"><a>Profile</a></li>
|
||||||
|
<li><a>Music</a></li>
|
||||||
|
<li><a>Videos</a></li>
|
||||||
|
<li><a>Documents</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
Loading…
Reference in New Issue