Add cottage calendar
This commit is contained in:
parent
2f27c6ee68
commit
9b1e9733a4
|
|
@ -0,0 +1,9 @@
|
||||||
|
-- Add down migration script here
|
||||||
|
-- Delete role records
|
||||||
|
DELETE FROM "main"."roles" WHERE "id" = '5';
|
||||||
|
|
||||||
|
-- Delete permission records
|
||||||
|
DELETE FROM "main"."role_permissions" WHERE "id" = '8';
|
||||||
|
|
||||||
|
-- Delete user role records
|
||||||
|
DELETE FROM "main"."user_roles" WHERE "role_id" = '5';
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
-- Add up migration script here
|
||||||
|
-- Add roles for calendar
|
||||||
|
INSERT INTO "main"."roles" ("id", "created_at", "created_by", "updated_at", "updated_by", "name", "description") VALUES ('5', '0', '0', '0', '0', 'calendar', 'Users with access to the calendar');
|
||||||
|
|
||||||
|
-- Add permissions for calendar
|
||||||
|
INSERT INTO "main"."role_permissions" ("id", "created_at", "created_by", "updated_at", "updated_by", "role_id", "item") VALUES ('8', '0', '0', '0', '0', '5', '/cottagecalendar');
|
||||||
|
|
||||||
|
-- Add user roles for calendar
|
||||||
|
INSERT INTO "main"."user_roles" ("id", "created_at", "created_by", "updated_at", "updated_by", "user_id", "role_id") VALUES ('1', '0', '0', '0', '0', '1', '5');
|
||||||
|
|
@ -15,7 +15,7 @@ mod user;
|
||||||
use error_handling::AppError;
|
use error_handling::AppError;
|
||||||
use middlewares::inject_user_data;
|
use middlewares::inject_user_data;
|
||||||
use google_oauth::{login, logout, google_auth_return};
|
use google_oauth::{login, logout, google_auth_return};
|
||||||
use routes::{dashboard, index, about, contact, profile, user_profile, useradmin};
|
use routes::{dashboard, index, about, cottagecalendar, contact, profile, user_profile, useradmin};
|
||||||
use user::{add_user_role, delete_user_role, UserData};
|
use user::{add_user_role, delete_user_role, UserData};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
@ -47,6 +47,7 @@ async fn main() {
|
||||||
// build our application with some routes
|
// build our application with some routes
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/dashboard", get(dashboard))
|
.route("/dashboard", get(dashboard))
|
||||||
|
.route("/cottagecalendar", get(cottagecalendar))
|
||||||
.route("/profile", get(profile))
|
.route("/profile", get(profile))
|
||||||
.route("/useradmin", get(useradmin))
|
.route("/useradmin", get(useradmin))
|
||||||
.route("/users/:user_id", get(user_profile))
|
.route("/users/:user_id", get(user_profile))
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,17 @@
|
||||||
use askama_axum::{Response, Template};
|
use askama_axum::{Response, Template};
|
||||||
use axum::{extract::{Path, State}, response::{Html, IntoResponse, Redirect}, Extension};
|
use axum::{
|
||||||
|
extract::{Path, State},
|
||||||
|
response::{Html, IntoResponse, Redirect},
|
||||||
|
Extension,
|
||||||
|
};
|
||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
use sqlx::SqlitePool;
|
use sqlx::SqlitePool;
|
||||||
|
|
||||||
use crate::{middlewares::is_authorized, user::{get_other_roles_display, get_user_roles_display}, UserData};
|
use crate::{
|
||||||
|
middlewares::is_authorized,
|
||||||
|
user::{get_other_roles_display, get_user_roles_display},
|
||||||
|
UserData,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "profile.html")]
|
#[template(path = "profile.html")]
|
||||||
|
|
@ -20,7 +28,7 @@ struct UserProfileTemplate {
|
||||||
name: String,
|
name: String,
|
||||||
user: UserData,
|
user: UserData,
|
||||||
user_roles: Vec<crate::user::UserRolesDisplay>,
|
user_roles: Vec<crate::user::UserRolesDisplay>,
|
||||||
non_user_roles: Vec<crate::user::UserRolesDisplay>
|
non_user_roles: Vec<crate::user::UserRolesDisplay>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HtmlTemplate<T>(T);
|
struct HtmlTemplate<T>(T);
|
||||||
|
|
@ -64,10 +72,10 @@ pub async fn index(
|
||||||
let name = user_name.unwrap_or_default();
|
let name = user_name.unwrap_or_default();
|
||||||
|
|
||||||
if is_authorized("/dashboard", user_data, db_pool).await {
|
if is_authorized("/dashboard", user_data, db_pool).await {
|
||||||
Redirect::to("/dashboard").into_response()
|
Redirect::to("/dashboard").into_response()
|
||||||
} else {
|
} else {
|
||||||
let template = IndexTemplate { logged_in, name };
|
let template = IndexTemplate { logged_in, name };
|
||||||
HtmlTemplate(template).into_response()
|
HtmlTemplate(template).into_response()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,7 +88,7 @@ pub async fn dashboard(
|
||||||
let name = user_name.unwrap_or_default();
|
let name = user_name.unwrap_or_default();
|
||||||
|
|
||||||
if is_authorized("/dashboard", user_data, db_pool).await {
|
if is_authorized("/dashboard", user_data, db_pool).await {
|
||||||
let template = DashboardTemplate { logged_in, name};
|
let template = DashboardTemplate { logged_in, name };
|
||||||
HtmlTemplate(template).into_response()
|
HtmlTemplate(template).into_response()
|
||||||
} else {
|
} else {
|
||||||
Redirect::to("/").into_response()
|
Redirect::to("/").into_response()
|
||||||
|
|
@ -96,15 +104,19 @@ pub async fn profile(
|
||||||
let user_name = user_data.as_ref().map(|s| s.name.clone());
|
let user_name = user_data.as_ref().map(|s| s.name.clone());
|
||||||
let logged_in = user_name.is_some();
|
let logged_in = user_name.is_some();
|
||||||
let name = user_name.unwrap_or_default();
|
let name = user_name.unwrap_or_default();
|
||||||
|
|
||||||
if logged_in {
|
if logged_in {
|
||||||
// Extract the user data.
|
// Extract the user data.
|
||||||
let user = user_data.as_ref().unwrap().clone();
|
let user = user_data.as_ref().unwrap().clone();
|
||||||
|
|
||||||
if is_authorized("/profile", user_data, db_pool).await {
|
if is_authorized("/profile", user_data, db_pool).await {
|
||||||
// Create the profile template.
|
// Create the profile template.
|
||||||
let template = ProfileTemplate { logged_in, name, user: user.clone() };
|
let template = ProfileTemplate {
|
||||||
return HtmlTemplate(template).into_response()
|
logged_in,
|
||||||
|
name,
|
||||||
|
user: user.clone(),
|
||||||
|
};
|
||||||
|
return HtmlTemplate(template).into_response();
|
||||||
} else {
|
} else {
|
||||||
Redirect::to("/").into_response()
|
Redirect::to("/").into_response()
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +125,7 @@ pub async fn profile(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn user_profile(
|
pub async fn user_profile(
|
||||||
Path(user_id): Path<i64>,
|
Path(user_id): Path<i64>,
|
||||||
State(db_pool): State<SqlitePool>,
|
State(db_pool): State<SqlitePool>,
|
||||||
Extension(user_data): Extension<Option<UserData>>,
|
Extension(user_data): Extension<Option<UserData>>,
|
||||||
|
|
@ -122,16 +134,12 @@ pub async fn profile(
|
||||||
let user_name = user_data.as_ref().map(|s| s.name.clone());
|
let user_name = user_data.as_ref().map(|s| s.name.clone());
|
||||||
let logged_in = user_data.is_some();
|
let logged_in = user_data.is_some();
|
||||||
let name = user_name.unwrap_or_default();
|
let name = user_name.unwrap_or_default();
|
||||||
|
|
||||||
// Extract the user data.
|
// Extract the user data.
|
||||||
let user = sqlx::query_as!(
|
let user = sqlx::query_as!(UserData, "SELECT * FROM users WHERE id = ?", user_id)
|
||||||
UserData,
|
.fetch_one(&db_pool)
|
||||||
"SELECT * FROM users WHERE id = ?",
|
.await
|
||||||
user_id
|
.unwrap();
|
||||||
)
|
|
||||||
.fetch_one(&db_pool)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if is_authorized("/users", user_data, db_pool.clone()).await {
|
if is_authorized("/users", user_data, db_pool.clone()).await {
|
||||||
// Get user roles
|
// Get user roles
|
||||||
|
|
@ -141,8 +149,14 @@ pub async fn profile(
|
||||||
let non_user_roles = get_other_roles_display(user_id, &db_pool.clone()).await;
|
let non_user_roles = get_other_roles_display(user_id, &db_pool.clone()).await;
|
||||||
|
|
||||||
// Create the profile template.
|
// Create the profile template.
|
||||||
let template = UserProfileTemplate { logged_in, name, user: user, user_roles , non_user_roles};
|
let template = UserProfileTemplate {
|
||||||
return HtmlTemplate(template).into_response()
|
logged_in,
|
||||||
|
name,
|
||||||
|
user: user,
|
||||||
|
user_roles,
|
||||||
|
non_user_roles,
|
||||||
|
};
|
||||||
|
return HtmlTemplate(template).into_response();
|
||||||
} else {
|
} else {
|
||||||
Redirect::to("/").into_response()
|
Redirect::to("/").into_response()
|
||||||
}
|
}
|
||||||
|
|
@ -153,25 +167,28 @@ pub async fn profile(
|
||||||
struct UserAdminTemplate {
|
struct UserAdminTemplate {
|
||||||
logged_in: bool,
|
logged_in: bool,
|
||||||
name: String,
|
name: String,
|
||||||
users: Vec<UserData>
|
users: Vec<UserData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn useradmin(
|
pub async fn useradmin(
|
||||||
Extension(user_data): Extension<Option<UserData>>,
|
Extension(user_data): Extension<Option<UserData>>,
|
||||||
State(db_pool): State<SqlitePool>,
|
State(db_pool): State<SqlitePool>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
|
|
||||||
let user_name = user_data.as_ref().map(|s| s.name.clone());
|
let user_name = user_data.as_ref().map(|s| s.name.clone());
|
||||||
let logged_in = user_name.is_some();
|
let logged_in = user_name.is_some();
|
||||||
let name = user_name.unwrap_or_default();
|
let name = user_name.unwrap_or_default();
|
||||||
|
|
||||||
let users = sqlx::query_as::<_, UserData>("SELECT * FROM users")
|
let users = sqlx::query_as::<_, UserData>("SELECT * FROM users")
|
||||||
.fetch_all(&db_pool)
|
.fetch_all(&db_pool)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
if is_authorized("/useradmin", user_data, db_pool).await {
|
if is_authorized("/useradmin", user_data, db_pool).await {
|
||||||
let template = UserAdminTemplate { logged_in, name, users };
|
let template = UserAdminTemplate {
|
||||||
|
logged_in,
|
||||||
|
name,
|
||||||
|
users,
|
||||||
|
};
|
||||||
HtmlTemplate(template).into_response()
|
HtmlTemplate(template).into_response()
|
||||||
} else {
|
} else {
|
||||||
Redirect::to("/").into_response()
|
Redirect::to("/").into_response()
|
||||||
|
|
@ -185,9 +202,7 @@ struct AboutTemplate {
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn about(
|
pub async fn about(Extension(user_data): Extension<Option<UserData>>) -> impl IntoResponse {
|
||||||
Extension(user_data): Extension<Option<UserData>>,
|
|
||||||
) -> impl IntoResponse {
|
|
||||||
let user_name = user_data.map(|s| s.name);
|
let user_name = user_data.map(|s| s.name);
|
||||||
let logged_in = user_name.is_some();
|
let logged_in = user_name.is_some();
|
||||||
let name = user_name.unwrap_or_default();
|
let name = user_name.unwrap_or_default();
|
||||||
|
|
@ -196,7 +211,6 @@ pub async fn about(
|
||||||
HtmlTemplate(template)
|
HtmlTemplate(template)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
#[template(path = "contactus.html")]
|
#[template(path = "contactus.html")]
|
||||||
struct ContactTemplate {
|
struct ContactTemplate {
|
||||||
|
|
@ -204,13 +218,34 @@ struct ContactTemplate {
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn contact(
|
pub async fn contact(Extension(user_data): Extension<Option<UserData>>) -> impl IntoResponse {
|
||||||
Extension(user_data): Extension<Option<UserData>>,
|
|
||||||
) -> impl IntoResponse {
|
|
||||||
let user_name = user_data.map(|s| s.name);
|
let user_name = user_data.map(|s| s.name);
|
||||||
let logged_in = user_name.is_some();
|
let logged_in = user_name.is_some();
|
||||||
let name = user_name.unwrap_or_default();
|
let name = user_name.unwrap_or_default();
|
||||||
|
|
||||||
let template = ContactTemplate { logged_in, name };
|
let template = ContactTemplate { logged_in, name };
|
||||||
HtmlTemplate(template)
|
HtmlTemplate(template)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "cottagecalendar.html")]
|
||||||
|
struct CottageCalendarTemplate {
|
||||||
|
logged_in: bool,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn cottagecalendar(
|
||||||
|
Extension(user_data): Extension<Option<UserData>>,
|
||||||
|
State(db_pool): State<SqlitePool>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let user_name = user_data.as_ref().map(|s| s.name.clone());
|
||||||
|
let logged_in = user_name.is_some();
|
||||||
|
let name = user_name.unwrap_or_default();
|
||||||
|
|
||||||
|
if is_authorized("/cottagecalendar", user_data, db_pool).await {
|
||||||
|
let template = CottageCalendarTemplate { logged_in, name };
|
||||||
|
HtmlTemplate(template).into_response()
|
||||||
|
} else {
|
||||||
|
Redirect::to("/").into_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="/dashboard">Web links</a></li>
|
<li><a href="/dashboard">Web links</a></li>
|
||||||
<li><a href="/useradmin">User Administration</a></li>
|
<li><a href="/useradmin">User Administration</a></li>
|
||||||
|
<li><a href="/cottagecalendar">Cottage Calendar</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-8">
|
<div class="col-8">
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
{% extends "authorized.html" %}
|
||||||
|
{% block center %}
|
||||||
|
<h1>Cottage Calendar</h1>
|
||||||
|
<div class="ratio ratio-4x3">
|
||||||
|
<!--<iframe src="https://calendar.google.com/calendar/embed?src=jeanmarie.cottage%40gmail.com&ctz=America%2FToronto" style="border: 0" width="800" height="400" frameborder="0" scrolling="no"></iframe>-->
|
||||||
|
<iframe width="300" height="430" src="https://nextcloud.jean-marie.ca/index.php/apps/calendar/embed/c3AGT6MXBPs8tzAC"></iframe>
|
||||||
|
</div>
|
||||||
|
{% endblock center %}
|
||||||
|
|
@ -5,17 +5,18 @@
|
||||||
<h2>Web links</h2>
|
<h2>Web links</h2>
|
||||||
<h3>TLC Creations</h3>
|
<h3>TLC Creations</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="https://www.tlccreations.ca">TLC Creations</a></li>
|
<li><a href="https://www.tlccreations.ca" target="_blank" rel="noopener noreferrer">TLC Creations</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<h3>Fonts</h3>
|
<h3>Fonts</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="https://fonts.google.com">Google fonts</a></li>
|
<li><a href="https://fonts.google.com" target="_blank" rel="noopener noreferrer">Google fonts</a></li>
|
||||||
<li><a href="https://www.fontspace.com">Font Space</a></li>
|
<li><a href="https://www.fontspace.com" target="_blank" rel="noopener noreferrer">Font Space</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<h3>Family tree</h3>
|
<h3>Family tree</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="https://www.ancestry.com">Ancestry</a></li>
|
<li><a href="https://www.ancestry.ca" target="_blank" rel="noopener noreferrer">Ancestry</a></li>
|
||||||
<li><a href="https://www.geni.com">Geni</a></li>
|
<li><a href="https://www.geni.com" target="_blank" rel="noopener noreferrer">Geni</a></li>
|
||||||
|
<li><a href="http://www.tracingroots.ca/" target="_blank" rel="noopener noreferrer">Tracing Roots - Forth Family Tree</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% endblock center %}
|
{% endblock center %}
|
||||||
Loading…
Reference in New Issue