aboutsummaryrefslogtreecommitdiff
path: root/server/src/routes/userdata.rs
blob: 22e20b7cbc9df313b47a2f876d5e845582707dc7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
    This file is part of jellything (https://codeberg.org/metamuffin/jellything)
    which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
    Copyright (C) 2024 metamuffin <metamuffin.org>
*/
use super::ui::{account::session::Session, error::MyResult, node::DatabaseNodeUserDataExt};
use crate::routes::ui::node::rocket_uri_macro_r_library_node;
use anyhow::anyhow;
use jellybase::{
    database::{redb::ReadableTable, DataAcid, Ser, TableExt, T_NODE, T_USER_NODE},
    permission::NodePermissionExt,
};
use jellycommon::user::{NodeUserData, WatchedState};
use rocket::{
    form::Form, get, post, response::Redirect, serde::json::Json, FromForm, FromFormField, State,
    UriDisplayQuery,
};

#[derive(Debug, FromFormField, UriDisplayQuery)]
pub enum UrlWatchedState {
    None,
    Watched,
    Pending,
}

#[get("/n/<id>/userdata")]
pub fn r_node_userdata(
    session: Session,
    db: &State<DataAcid>,
    id: &str,
) -> MyResult<Json<NodeUserData>> {
    let (_, _, u) = db.get_node_with_userdata(id, &session)?;
    Ok(Json(u))
}

#[post("/n/<id>/watched?<state>")]
pub async fn r_node_userdata_watched(
    session: Session,
    db: &State<DataAcid>,
    id: &str,
    state: UrlWatchedState,
) -> MyResult<Redirect> {
    T_NODE
        .get(db, id)?
        .only_if_permitted(&session.user.permissions)
        .ok_or(anyhow!("node does not exist"))?;

    let txn = db.begin_write()?;
    let mut user_nodes = txn.open_table(T_USER_NODE)?;

    let mut udata = user_nodes
        .get((session.user.name.as_str(), id))?
        .map(|x| x.value().0)
        .unwrap_or_default();

    udata.watched = match state {
        UrlWatchedState::None => WatchedState::None,
        UrlWatchedState::Watched => WatchedState::Watched,
        UrlWatchedState::Pending => WatchedState::Pending,
    };

    user_nodes.insert((session.user.name.as_str(), id), Ser(udata))?;
    drop(user_nodes);
    txn.commit()?;

    Ok(Redirect::found(rocket::uri!(r_library_node(id))))
}

#[derive(FromForm)]
pub struct UpdateRating {
    #[field(validate = range(-10..=10))]
    rating: i32,
}

#[post("/n/<id>/update_rating", data = "<form>")]
pub async fn r_node_userdata_rating(
    session: Session,
    db: &State<DataAcid>,
    id: &str,
    form: Form<UpdateRating>,
) -> MyResult<Redirect> {
    T_NODE
        .get(db, id)?
        .only_if_permitted(&session.user.permissions)
        .ok_or(anyhow!("node does not exist"))?;

    let txn = db.begin_write()?;
    let mut user_nodes = txn.open_table(T_USER_NODE)?;

    let mut udata = user_nodes
        .get((session.user.name.as_str(), id))?
        .map(|x| x.value().0)
        .unwrap_or_default();

    udata.rating = form.rating;

    user_nodes.insert((session.user.name.as_str(), id), Ser(udata))?;
    drop(user_nodes);
    txn.commit()?;

    Ok(Redirect::found(rocket::uri!(r_library_node(id))))
}

#[post("/n/<id>/progress?<t>")]
pub async fn r_node_userdata_progress(
    session: Session,
    db: &State<DataAcid>,
    id: &str,
    t: f64,
) -> MyResult<()> {
    T_NODE
        .get(db, id)?
        .only_if_permitted(&session.user.permissions)
        .ok_or(anyhow!("node does not exist"))?;

    let txn = db.begin_write()?;
    let mut user_nodes = txn.open_table(T_USER_NODE)?;

    let mut udata = user_nodes
        .get((session.user.name.as_str(), id))?
        .map(|x| x.value().0)
        .unwrap_or_default();

    udata.watched = match udata.watched {
        WatchedState::None | WatchedState::Pending | WatchedState::Progress(_) => {
            WatchedState::Progress(t)
        }
        WatchedState::Watched => WatchedState::Watched,
    };

    user_nodes.insert((session.user.name.as_str(), id), Ser(udata))?;
    drop(user_nodes);
    txn.commit()?;

    Ok(())
}