ctoolbox/io/webui/controllers/
graph.rs1use std::io::Read;
2
3use axum::Form;
4use axum::body::Bytes;
5use axum::extract::{Query, State};
6use axum::response::{IntoResponse, Redirect, Response};
7use axum_typed_multipart::{TryFromMultipart, TypedMultipart};
8use serde::Deserialize;
9
10use crate::io::webui::{
11 AppState, AuthenticatedUser, PageQuery, RequestState, error_400, error_403,
12 respond_page,
13};
14use crate::io::webui::controllers::base::{redirect_temporary};
15use crate::utilities::strtovec;
16use crate::{get_user_and_graph, json_value};
17
18pub async fn get_nodes_index(
19 State(state): State<AppState>,
20 req: RequestState,
21 _q: Query<PageQuery>,
22) -> Response {
23 respond_page(&state, req, "nodes.index", &json_value!({}))
24}
25
26pub async fn get_nodes_view(
27 State(state): State<AppState>,
28 req: RequestState,
29 _q: Query<PageQuery>,
30) -> Response {
31 respond_page(&state, req, "nodes.view", &json_value!({}))
32}
33
34pub async fn get_nodes_create(
35 State(state): State<AppState>,
36 req: RequestState,
37) -> Response {
38 respond_page(&state, req, "nodes.create", &json_value!({}))
39}
40
41#[derive(Deserialize)]
42pub struct CreateNodeForm {
43 graph: u32,
44 node_type: String,
45 node_content: String,
46}
47
48pub async fn post_nodes_create(
49 State(state): State<AppState>,
50 req: RequestState,
51 sess: AuthenticatedUser,
52 Form(input): Form<CreateNodeForm>,
53) -> Response {
54 get_user_and_graph!(&state, &req, sess, input.graph, user, graph);
55
56 if let Err(e) = graph.create_node(
57 &user,
58 input.node_type.as_str(),
59 strtovec(input.node_content.as_str()).as_slice(),
60 ) {
61 return error_400(&state, &req, e);
62 }
63
64 redirect_temporary(req.is_js_request, "/nodes")
65}
66
67pub async fn get_nodes_upload(
68 State(state): State<AppState>,
69 req: RequestState,
70) -> Response {
71 respond_page(&state, req, "nodes.upload", &json_value!({}))
72}
73
74#[derive(TryFromMultipart)]
75#[try_from_multipart(strict)]
76pub struct UploadNodeForm {
77 graph: u32,
78 node_type: String,
79 #[form_data(limit = "unlimited")]
80 node_content: Bytes,
81}
82
83struct ReadableBytes {
85 inner: Bytes,
86}
87
88impl Read for ReadableBytes {
90 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
91 let len = std::cmp::min(buf.len(), self.inner.len());
92 buf[..len].copy_from_slice(&self.inner[..len]);
93 self.inner = self.inner.slice(len..);
94 Ok(len)
95 }
96}
97
98impl ReadableBytes {
99 fn new(bytes: Bytes) -> Self {
100 Self { inner: bytes }
101 }
102}
103
104pub async fn post_nodes_upload(
105 State(state): State<AppState>,
106 req: RequestState,
107 sess: AuthenticatedUser,
108 TypedMultipart(form): TypedMultipart<UploadNodeForm>,
109) -> Response {
110 get_user_and_graph!(&state, &req, sess, form.graph, user, graph);
111 let readable_bytes = ReadableBytes::new(form.node_content);
112
113 if let Err(e) =
114 graph.create_node(&user, form.node_type.as_str(), readable_bytes)
115 {
116 return error_400(&state, &req, e);
117 }
118
119 redirect_temporary(req.is_js_request, "/nodes")
120}