Added begin of messaging proposal
This commit is contained in:
parent
a75df84dcb
commit
924b98f7e6
@ -2,5 +2,5 @@ pub mod admin;
|
|||||||
pub mod agenda;
|
pub mod agenda;
|
||||||
pub mod home;
|
pub mod home;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
pub mod news;
|
pub mod messages;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
|
@ -17,10 +17,10 @@ pub fn Navbar() -> Element {
|
|||||||
"Home"
|
"Home"
|
||||||
},
|
},
|
||||||
Link {
|
Link {
|
||||||
to: Route::News {},
|
to: Route::MessagesPage {},
|
||||||
class: "btn btn-ghost flex-col flex-nowrap py-1 gap-1 font-normal h-max",
|
class: "btn btn-ghost flex-col flex-nowrap py-1 gap-1 font-normal h-max",
|
||||||
icons::Newspaper {},
|
icons::Newspaper {},
|
||||||
div { class: "font-normal", "Nieuws" }
|
div { class: "font-normal", "Berichten" }
|
||||||
},
|
},
|
||||||
Link {
|
Link {
|
||||||
to: Route::Agenda {},
|
to: Route::Agenda {},
|
||||||
|
@ -3,7 +3,7 @@ use dioxus::prelude::*;
|
|||||||
pub mod create;
|
pub mod create;
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn News() -> Element {
|
pub fn MessagesPage() -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
h1 { class: "text-xl font-bold text-primary", "Nieuws" }
|
h1 { class: "text-xl font-bold text-primary", "Nieuws" }
|
126
src/components/messages/create.rs
Normal file
126
src/components/messages/create.rs
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
use crate::util::model::message::{Message, Target, TargetKind};
|
||||||
|
use crate::util::model::session::Session;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
mod content;
|
||||||
|
mod targets;
|
||||||
|
|
||||||
|
#[derive(PartialEq)]
|
||||||
|
enum Steps {
|
||||||
|
Message,
|
||||||
|
Targets,
|
||||||
|
Verify,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Props, Clone, PartialEq, Debug)]
|
||||||
|
struct Form {
|
||||||
|
title: Signal<String>,
|
||||||
|
body: Signal<String>,
|
||||||
|
targets: Signal<HashMap<u32, Target>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Form {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
title: use_signal(|| String::new()),
|
||||||
|
body: use_signal(|| String::new()),
|
||||||
|
targets: use_signal(|| {
|
||||||
|
HashMap::from([(
|
||||||
|
0,
|
||||||
|
Target {
|
||||||
|
kind: TargetKind::None,
|
||||||
|
value: String::new(),
|
||||||
|
},
|
||||||
|
)])
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn MessagesCreatePage() -> Element {
|
||||||
|
let mut step = use_signal(|| Steps::Message);
|
||||||
|
let form = Form::default();
|
||||||
|
|
||||||
|
let submit_proposal = move |_| async move {
|
||||||
|
let targets = (form.targets)();
|
||||||
|
|
||||||
|
if let Ok(amount) = message_proposal(
|
||||||
|
(form.title)(),
|
||||||
|
(form.body)(),
|
||||||
|
targets.into_values().collect(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
tracing::info!("{}", amount);
|
||||||
|
step.set(Steps::Verify);
|
||||||
|
} else {
|
||||||
|
tracing::info!("Error occured")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
div {
|
||||||
|
class: "w-full max-w-2xl space-y-3 flex flex-col",
|
||||||
|
h1 { class: "text-xl font-bold text-primary", "Nieuw bericht" }
|
||||||
|
ul {
|
||||||
|
class: "steps pb-10 mx-auto",
|
||||||
|
li { class: "step step-primary", "Inhoud" },
|
||||||
|
li {
|
||||||
|
class: "step",
|
||||||
|
class: if let Steps::Targets | Steps::Done | Steps::Verify = *step.read() { "step-primary" },
|
||||||
|
"Naar"
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
class: "step",
|
||||||
|
class: if let Steps::Verify | Steps::Done = *step.read() { "step-primary" },
|
||||||
|
"Controleren"
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
class: "step",
|
||||||
|
class: if let Steps::Done = *step.read() { "step-primary" },
|
||||||
|
"Klaar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
class: "flex flex-col gap-y-5",
|
||||||
|
div {
|
||||||
|
class: if let Steps::Message = *step.read() { "" } else { "hidden" },
|
||||||
|
content::Content {
|
||||||
|
step: step,
|
||||||
|
title: form.title,
|
||||||
|
body: form.body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
class: if let Steps::Targets = *step.read() { "" } else { "hidden" },
|
||||||
|
targets::Targets {
|
||||||
|
step: step,
|
||||||
|
targets: form.targets,
|
||||||
|
onsubmit: submit_proposal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[server]
|
||||||
|
async fn message_proposal(
|
||||||
|
title: String,
|
||||||
|
body: String,
|
||||||
|
targets: Vec<Target>,
|
||||||
|
) -> Result<usize, ServerFnError> {
|
||||||
|
let user = Session::fetch_current_user().await?;
|
||||||
|
|
||||||
|
if !user.admin {
|
||||||
|
return Err(crate::Error::NoPermissions.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let amount = Message::create_proposal(title, body, targets).await?;
|
||||||
|
|
||||||
|
Ok(amount)
|
||||||
|
}
|
51
src/components/messages/create/content.rs
Normal file
51
src/components/messages/create/content.rs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
use super::Steps;
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Content(step: Signal<Steps>, title: Signal<String>, body: Signal<String>) -> Element {
|
||||||
|
let submit = move |event: FormEvent| {
|
||||||
|
title.set(event.values()["title"].as_value());
|
||||||
|
body.set(event.values()["body"].as_value());
|
||||||
|
step.set(Steps::Targets);
|
||||||
|
};
|
||||||
|
|
||||||
|
rsx! {
|
||||||
|
form {
|
||||||
|
class: "flex flex-col w-full gap-y-5",
|
||||||
|
onsubmit: submit,
|
||||||
|
label {
|
||||||
|
class: "form-control w-full",
|
||||||
|
div {
|
||||||
|
class: "label",
|
||||||
|
span { class: "label-text", "Titel" }
|
||||||
|
},
|
||||||
|
input {
|
||||||
|
r#type: "text",
|
||||||
|
required: true,
|
||||||
|
name: "title",
|
||||||
|
class: "input input-bordered w-full",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
class: "form-control w-full",
|
||||||
|
div {
|
||||||
|
class: "label",
|
||||||
|
span { class: "label-text", "Bericht" }
|
||||||
|
},
|
||||||
|
textarea {
|
||||||
|
name: "body",
|
||||||
|
class: "textarea textarea-bordered w-full",
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
div {
|
||||||
|
class: "w-full flex gap-x-3 justify-end",
|
||||||
|
input {
|
||||||
|
r#type: "submit",
|
||||||
|
class: "btn btn-primary",
|
||||||
|
value: "Volgende",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,142 +1,15 @@
|
|||||||
use crate::util::model::news::{Target, TargetKind};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
use super::Steps;
|
||||||
enum Steps {
|
use crate::util::model::message::{Message, Target, TargetKind};
|
||||||
Message,
|
use std::collections::HashMap;
|
||||||
Targets,
|
|
||||||
Verify,
|
|
||||||
Done,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Props, Clone, PartialEq, Debug)]
|
#[component]
|
||||||
struct Form {
|
pub fn Targets(
|
||||||
title: Signal<String>,
|
step: Signal<Steps>,
|
||||||
body: Signal<String>,
|
|
||||||
targets: Signal<HashMap<u32, Target>>,
|
targets: Signal<HashMap<u32, Target>>,
|
||||||
}
|
onsubmit: EventHandler<FormEvent>,
|
||||||
|
) -> Element {
|
||||||
impl Default for Form {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
title: use_signal(|| String::new()),
|
|
||||||
body: use_signal(|| String::new()),
|
|
||||||
targets: use_signal(|| {
|
|
||||||
HashMap::from([(
|
|
||||||
0,
|
|
||||||
Target {
|
|
||||||
kind: TargetKind::None,
|
|
||||||
value: String::new(),
|
|
||||||
},
|
|
||||||
)])
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[component]
|
|
||||||
pub fn NewsCreate() -> Element {
|
|
||||||
let step = use_signal(|| Steps::Message);
|
|
||||||
let form = Form::default();
|
|
||||||
|
|
||||||
rsx! {
|
|
||||||
div {
|
|
||||||
class: "w-full max-w-2xl space-y-3 flex flex-col",
|
|
||||||
h1 { class: "text-xl font-bold text-primary", "Nieuw bericht" }
|
|
||||||
ul {
|
|
||||||
class: "steps pb-10 mx-auto",
|
|
||||||
li { class: "step step-primary", "Inhoud" },
|
|
||||||
li {
|
|
||||||
class: "step",
|
|
||||||
class: if let Steps::Targets | Steps::Done | Steps::Verify = *step.read() { "step-primary" },
|
|
||||||
"Naar"
|
|
||||||
}
|
|
||||||
li {
|
|
||||||
class: "step",
|
|
||||||
class: if let Steps::Verify | Steps::Done = *step.read() { "step-primary" },
|
|
||||||
"Controleren"
|
|
||||||
}
|
|
||||||
li {
|
|
||||||
class: "step",
|
|
||||||
class: if let Steps::Done = *step.read() { "step-primary" },
|
|
||||||
"Klaar"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div {
|
|
||||||
class: "flex flex-col gap-y-5",
|
|
||||||
div {
|
|
||||||
class: if let Steps::Message = *step.read() { "" } else { "hidden" },
|
|
||||||
Message {
|
|
||||||
step: step,
|
|
||||||
title: form.title,
|
|
||||||
body: form.body,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
div {
|
|
||||||
class: if let Steps::Targets = *step.read() { "" } else { "hidden" },
|
|
||||||
TargetSelect {
|
|
||||||
step: step,
|
|
||||||
targets: form.targets,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[component]
|
|
||||||
fn Message(step: Signal<Steps>, title: Signal<String>, body: Signal<String>) -> Element {
|
|
||||||
let submit = move |event: FormEvent| {
|
|
||||||
title.set(event.values()["title"].as_value());
|
|
||||||
body.set(event.values()["body"].as_value());
|
|
||||||
step.set(Steps::Targets);
|
|
||||||
};
|
|
||||||
|
|
||||||
rsx! {
|
|
||||||
form {
|
|
||||||
class: "flex flex-col w-full gap-y-5",
|
|
||||||
onsubmit: submit,
|
|
||||||
label {
|
|
||||||
class: "form-control w-full",
|
|
||||||
div {
|
|
||||||
class: "label",
|
|
||||||
span { class: "label-text", "Titel" }
|
|
||||||
},
|
|
||||||
input {
|
|
||||||
r#type: "text",
|
|
||||||
required: true,
|
|
||||||
name: "title",
|
|
||||||
class: "input input-bordered w-full",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
label {
|
|
||||||
class: "form-control w-full",
|
|
||||||
div {
|
|
||||||
class: "label",
|
|
||||||
span { class: "label-text", "Bericht" }
|
|
||||||
},
|
|
||||||
textarea {
|
|
||||||
name: "body",
|
|
||||||
class: "textarea textarea-bordered w-full",
|
|
||||||
required: true,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
div {
|
|
||||||
class: "w-full flex gap-x-3 justify-end",
|
|
||||||
input {
|
|
||||||
r#type: "submit",
|
|
||||||
class: "btn btn-primary",
|
|
||||||
value: "Volgende",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[component]
|
|
||||||
fn TargetSelect(step: Signal<Steps>, targets: Signal<HashMap<u32, Target>>) -> Element {
|
|
||||||
let mut target_id = use_signal(|| 1);
|
let mut target_id = use_signal(|| 1);
|
||||||
|
|
||||||
let target_ids = use_memo(move || {
|
let target_ids = use_memo(move || {
|
||||||
@ -147,14 +20,10 @@ fn TargetSelect(step: Signal<Steps>, targets: Signal<HashMap<u32, Target>>) -> E
|
|||||||
filtered_targets
|
filtered_targets
|
||||||
});
|
});
|
||||||
|
|
||||||
let submit = move |_| {
|
|
||||||
step.set(Steps::Verify);
|
|
||||||
};
|
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
form {
|
form {
|
||||||
class: "w-full",
|
class: "w-full",
|
||||||
onsubmit: submit,
|
onsubmit: move |event| onsubmit.call(event),
|
||||||
label {
|
label {
|
||||||
class: "form-control w-full",
|
class: "form-control w-full",
|
||||||
div {
|
div {
|
12
src/main.rs
12
src/main.rs
@ -18,8 +18,8 @@ use components::agenda::Agenda;
|
|||||||
use components::home::Home;
|
use components::home::Home;
|
||||||
use components::layout::AdminLayout;
|
use components::layout::AdminLayout;
|
||||||
use components::layout::Global;
|
use components::layout::Global;
|
||||||
use components::news::create::NewsCreate;
|
use components::messages::create::MessagesCreatePage;
|
||||||
use components::news::News;
|
use components::messages::MessagesPage;
|
||||||
use components::settings::Settings;
|
use components::settings::Settings;
|
||||||
use tracing::Level;
|
use tracing::Level;
|
||||||
|
|
||||||
@ -31,10 +31,10 @@ pub enum Route {
|
|||||||
Home {},
|
Home {},
|
||||||
#[route("/agenda")]
|
#[route("/agenda")]
|
||||||
Agenda {},
|
Agenda {},
|
||||||
#[route("/news")]
|
#[route("/messages")]
|
||||||
News {},
|
MessagesPage {},
|
||||||
#[route("/news/create")]
|
#[route("/messages/create")]
|
||||||
NewsCreate {},
|
MessagesCreatePage {},
|
||||||
#[route("/settings")]
|
#[route("/settings")]
|
||||||
Settings {},
|
Settings {},
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
pub mod member;
|
pub mod member;
|
||||||
pub mod news;
|
pub mod message;
|
||||||
pub mod session;
|
pub mod session;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
147
src/util/model/message.rs
Normal file
147
src/util/model/message.rs
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
use crate::util::surrealdb::{thing_to_string, DB};
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
use surrealdb::sql::statements::{BeginStatement, CommitStatement};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct PushSubscription {
|
||||||
|
endpoint: String,
|
||||||
|
keys_256dh: String,
|
||||||
|
keys_auth: String,
|
||||||
|
encodings: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Clone, Copy, Debug, Deserialize, Serialize, Eq)]
|
||||||
|
pub enum TargetKind {
|
||||||
|
None,
|
||||||
|
All,
|
||||||
|
Group,
|
||||||
|
Hourgroup,
|
||||||
|
Hour,
|
||||||
|
Member,
|
||||||
|
Account,
|
||||||
|
Day,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TargetKind {
|
||||||
|
pub fn from_string(input: &str) -> Self {
|
||||||
|
match input {
|
||||||
|
"all" => Self::All,
|
||||||
|
"group" => Self::Group,
|
||||||
|
"hourgroup" => Self::Hourgroup,
|
||||||
|
"hour" => Self::Hour,
|
||||||
|
"member" => Self::Member,
|
||||||
|
"account" => Self::Account,
|
||||||
|
"day" => Self::Day,
|
||||||
|
_ => Self::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug, Deserialize, Serialize, Clone, Eq)]
|
||||||
|
pub struct Target {
|
||||||
|
pub kind: TargetKind,
|
||||||
|
pub value: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
|
||||||
|
pub struct Message {
|
||||||
|
#[cfg_attr(feature = "server", serde(deserialize_with = "thing_to_string"))]
|
||||||
|
pub id: String,
|
||||||
|
pub title: String,
|
||||||
|
pub body: String,
|
||||||
|
pub tagets: Vec<Target>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
impl Message {
|
||||||
|
pub async fn create_proposal(
|
||||||
|
title: String,
|
||||||
|
body: String,
|
||||||
|
targets: Vec<Target>,
|
||||||
|
) -> Result<usize, crate::Error> {
|
||||||
|
let member_ids = fetch_members(targets).await?;
|
||||||
|
|
||||||
|
Ok(member_ids.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn insert(
|
||||||
|
title: String,
|
||||||
|
body: String,
|
||||||
|
channel: String,
|
||||||
|
member_ids: Vec<String>,
|
||||||
|
) -> Result<(), crate::Error> {
|
||||||
|
let mut transaction = DB
|
||||||
|
.query(BeginStatement::default())
|
||||||
|
.query("let $message = CREATE ONLY message SET title = $title, body = $body, channel = $channel RETURN id;")
|
||||||
|
.bind(("title", title))
|
||||||
|
.bind(("body", body))
|
||||||
|
.bind(("channel", channel));
|
||||||
|
|
||||||
|
for member_id in member_ids {
|
||||||
|
transaction = transaction.query(format!("RELATE ONLY (type::thing('member', $member_id_{}))->member_to_message->(type::thing('message', $message.id));", member_id))
|
||||||
|
.bind((format!("member_id_{}", member_id), member_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = transaction.query(CommitStatement::default()).await?;
|
||||||
|
|
||||||
|
res.check()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve a vec of all the members that will recieve the message
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
async fn fetch_members(targets: Vec<Target>) -> Result<Vec<String>, surrealdb::Error> {
|
||||||
|
let mut transaction = DB.query(BeginStatement::default());
|
||||||
|
|
||||||
|
for target in targets {
|
||||||
|
match target.kind {
|
||||||
|
TargetKind::All => {
|
||||||
|
transaction = transaction.query("SELECT VALUE meta::id(id) FROM member;");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut res = transaction.query(CommitStatement::default()).await?;
|
||||||
|
|
||||||
|
res = res.check()?;
|
||||||
|
|
||||||
|
let members: Vec<String> = res.take(0)?;
|
||||||
|
|
||||||
|
Ok(members)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "server")]
|
||||||
|
async fn fetch_pushsubscriptions(
|
||||||
|
targets: Vec<Target>,
|
||||||
|
) -> Result<Vec<PushSubscription>, surrealdb::Error> {
|
||||||
|
let mut transaction = DB.query(BeginStatement::default());
|
||||||
|
|
||||||
|
for target in targets {
|
||||||
|
match target.kind {
|
||||||
|
TargetKind::All => {
|
||||||
|
transaction = transaction
|
||||||
|
.query("RETURN array::group(SELECT VALUE pushsubscriptions FROM user);");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut res = transaction
|
||||||
|
.query(CommitStatement::default())
|
||||||
|
.await?
|
||||||
|
.check()?;
|
||||||
|
|
||||||
|
let pushsubscriptions: Vec<PushSubscription> = res.take(0)?;
|
||||||
|
|
||||||
|
Ok(pushsubscriptions)
|
||||||
|
}
|
@ -1,68 +0,0 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
use crate::util::surrealdb::{thing_to_string, DB};
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
use surrealdb::sql::{
|
|
||||||
statements::{BeginStatement, CommitStatement},
|
|
||||||
Thing,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Copy, Debug, Deserialize, Serialize, Eq)]
|
|
||||||
pub enum TargetKind {
|
|
||||||
None,
|
|
||||||
All,
|
|
||||||
Group,
|
|
||||||
Hourgroup,
|
|
||||||
Hour,
|
|
||||||
Member,
|
|
||||||
Account,
|
|
||||||
Day,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TargetKind {
|
|
||||||
pub fn from_string(input: &str) -> Self {
|
|
||||||
match input {
|
|
||||||
"all" => Self::All,
|
|
||||||
"group" => Self::Group,
|
|
||||||
"hourgroup" => Self::Hourgroup,
|
|
||||||
"hour" => Self::Hour,
|
|
||||||
"member" => Self::Member,
|
|
||||||
"account" => Self::Account,
|
|
||||||
"day" => Self::Day,
|
|
||||||
_ => Self::None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Deserialize, Serialize, Clone, Eq)]
|
|
||||||
pub struct Target {
|
|
||||||
pub kind: TargetKind,
|
|
||||||
pub value: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
|
|
||||||
pub struct News {
|
|
||||||
#[cfg_attr(feature = "server", serde(deserialize_with = "thing_to_string"))]
|
|
||||||
pub id: String,
|
|
||||||
pub title: String,
|
|
||||||
pub body: String,
|
|
||||||
pub tagets: Vec<Target>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
impl News {
|
|
||||||
// pub async fn new(
|
|
||||||
// title: String,
|
|
||||||
// body: String,
|
|
||||||
// targets: Vec<Target>,
|
|
||||||
// ) -> Result<Self, crate::Error> {
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
fn fetch_targets(targets: Vec<Target>) {
|
|
||||||
let mut transaction = DB.query(BeginStatement::default());
|
|
||||||
|
|
||||||
for target in targets {}
|
|
||||||
}
|
|
@ -8,6 +8,8 @@ use surrealdb::sql::{
|
|||||||
Thing,
|
Thing,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::message::PushSubscription;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
|
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
#[cfg_attr(feature = "server", serde(deserialize_with = "thing_to_string"))]
|
#[cfg_attr(feature = "server", serde(deserialize_with = "thing_to_string"))]
|
||||||
@ -174,4 +176,19 @@ impl User {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn insert_pushsubscription(
|
||||||
|
&self,
|
||||||
|
pushsubscription: PushSubscription,
|
||||||
|
) -> Result<(), crate::Error> {
|
||||||
|
let res = DB
|
||||||
|
.query("UPDATE $user SET pushsubscriptions += $pushsubscription;")
|
||||||
|
.bind(("user", Thing::from(("user", self.id.as_str()))))
|
||||||
|
.bind(("pushsubscription", pushsubscription))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
res.check()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,12 @@ async fn apply_queries() -> surrealdb::Result<()> {
|
|||||||
DEFINE FIELD password ON TABLE user TYPE string;
|
DEFINE FIELD password ON TABLE user TYPE string;
|
||||||
DEFINE FIELD admin ON TABLE user TYPE bool
|
DEFINE FIELD admin ON TABLE user TYPE bool
|
||||||
DEFAULT false;
|
DEFAULT false;
|
||||||
|
DEFINE FIELD pushsubscriptions ON TABLE user TYPE array<object>
|
||||||
|
DEFAULT [];
|
||||||
|
DEFINE FIELD pushsubscriptions.*.endpoint ON TABLE user TYPE string;
|
||||||
|
DEFINE FIELD pushsubscriptions.*.keys_256dh ON TABLE user TYPE string;
|
||||||
|
DEFINE FIELD pushsubscriptions.*.keys_auth ON TABLE user TYPE string;
|
||||||
|
DEFINE FIELD pushsubscriptions.*.encodings ON TABLE user TYPE string;
|
||||||
|
|
||||||
DEFINE INDEX userEmailIndex ON TABLE user COLUMNS email UNIQUE;
|
DEFINE INDEX userEmailIndex ON TABLE user COLUMNS email UNIQUE;
|
||||||
",
|
",
|
||||||
@ -94,5 +100,19 @@ async fn apply_queries() -> surrealdb::Result<()> {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
// Define messages table
|
||||||
|
DB.query(
|
||||||
|
"
|
||||||
|
DEFINE TABLE OVERWRITE message SCHEMAFULL;
|
||||||
|
|
||||||
|
DEFINE FIELD title ON TABLE message TYPE string;
|
||||||
|
DEFINE FIELD body ON TABLE message TYPE string;
|
||||||
|
DEFINE FIELD channel ON TABLE message TYPE string;
|
||||||
|
|
||||||
|
DEFINE TABLE OVERWRITE member_to_message SCHEMAFULL TYPE RELATION FROM member TO message ENFORCED;
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user