add: patch method on stream key
This commit is contained in:
Generated
+1
@@ -2879,6 +2879,7 @@ dependencies = [
|
|||||||
"migration",
|
"migration",
|
||||||
"opus",
|
"opus",
|
||||||
"rand 0.10.1",
|
"rand 0.10.1",
|
||||||
|
"regex",
|
||||||
"rml_rtmp",
|
"rml_rtmp",
|
||||||
"rubato",
|
"rubato",
|
||||||
"sea-orm",
|
"sea-orm",
|
||||||
|
|||||||
@@ -79,3 +79,14 @@ impl Entity {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ActiveModel {
|
||||||
|
pub async fn change_label_value(
|
||||||
|
mut self,
|
||||||
|
db: &DatabaseConnection,
|
||||||
|
value: String,
|
||||||
|
) -> Result<Model, DbErr> {
|
||||||
|
self.label = Set(value);
|
||||||
|
self.update(db).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,3 +35,4 @@ symphonia = { version = "0.5", features = ["aac"] }
|
|||||||
opus = "0.3.1"
|
opus = "0.3.1"
|
||||||
rubato = "3.0.0"
|
rubato = "3.0.0"
|
||||||
chrono = "0.4.45"
|
chrono = "0.4.45"
|
||||||
|
regex = "1"
|
||||||
|
|||||||
@@ -1,11 +1,21 @@
|
|||||||
use std::{
|
use std::{
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
sync::{
|
sync::{
|
||||||
Arc,
|
Arc, LazyLock,
|
||||||
atomic::{AtomicI32, Ordering},
|
atomic::{AtomicI32, Ordering},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
// The Rust `regex` crate is guaranteed linear-time and therefore does NOT
|
||||||
|
// support lookaround, so the JS source pattern
|
||||||
|
// /^(?=.*[A-Za-z])[A-Za-z0-9_-]{1,67}$/
|
||||||
|
// cannot be ported verbatim. The `(?=.*[A-Za-z])` lookahead only means
|
||||||
|
// "must contain at least one letter" — we drop it from the pattern and
|
||||||
|
// enforce that condition with a separate `.chars().any(..)` check below.
|
||||||
|
static KEY_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"^[A-Za-z0-9 _-]{1,67}$").unwrap());
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
Json, Router,
|
Json, Router,
|
||||||
body::{Body, Bytes},
|
body::{Body, Bytes},
|
||||||
@@ -20,7 +30,9 @@ use axum::{
|
|||||||
};
|
};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use entity::{auth_session, stream_key, stream_session, users};
|
use entity::{auth_session, stream_key, stream_session, users};
|
||||||
use sea_orm::{DatabaseConnection, EntityTrait, QueryFilter, prelude::DateTimeUtc};
|
use sea_orm::{
|
||||||
|
DatabaseConnection, EntityTrait, IntoActiveModel, QueryFilter, prelude::DateTimeUtc,
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
net::TcpListener,
|
net::TcpListener,
|
||||||
@@ -83,7 +95,9 @@ impl HttpServer {
|
|||||||
.route("/api/user", post(create_user_handler))
|
.route("/api/user", post(create_user_handler))
|
||||||
.route(
|
.route(
|
||||||
"/api/stream-key",
|
"/api/stream-key",
|
||||||
post(create_stream_key_handler).get(get_all_stream_keys),
|
post(create_stream_key_handler)
|
||||||
|
.get(get_all_stream_keys)
|
||||||
|
.patch(edit_stream_key),
|
||||||
)
|
)
|
||||||
// .route("/api/admin/server_stats", get(todo!()))
|
// .route("/api/admin/server_stats", get(todo!()))
|
||||||
.route("/api/whip", post(handle_whip_injest))
|
.route("/api/whip", post(handle_whip_injest))
|
||||||
@@ -112,6 +126,48 @@ struct StreamListing {
|
|||||||
started_at: DateTime<Utc>, //UNIX TIMESTAMP
|
started_at: DateTime<Utc>, //UNIX TIMESTAMP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct EditStreamKeyRequest {
|
||||||
|
id: i32,
|
||||||
|
new: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn edit_stream_key(
|
||||||
|
State(state): State<Arc<HttpServer>>,
|
||||||
|
auth: AuthUser,
|
||||||
|
Json(payload): Json<EditStreamKeyRequest>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
// Trim surrounding whitespace so labels aren't stored with leading/trailing spaces.
|
||||||
|
let new_label = payload.new.trim();
|
||||||
|
// Length (1..=67) and allowed charset ([A-Za-z0-9 _-], space included).
|
||||||
|
if !KEY_RE.is_match(new_label) {
|
||||||
|
return (StatusCode::BAD_REQUEST, "invalid label").into_response();
|
||||||
|
}
|
||||||
|
// Replaces the JS lookahead: label must contain at least one letter.
|
||||||
|
if !new_label.chars().any(|c| c.is_ascii_alphabetic()) {
|
||||||
|
return (StatusCode::BAD_REQUEST, "label must contain a letter").into_response();
|
||||||
|
}
|
||||||
|
|
||||||
|
let stream_key_id_result = stream_key::Entity::find_by_id(payload.id)
|
||||||
|
.one(&state.db)
|
||||||
|
.await;
|
||||||
|
if stream_key_id_result.is_err() {
|
||||||
|
return StatusCode::INTERNAL_SERVER_ERROR.into_response();
|
||||||
|
}
|
||||||
|
let stream_key = stream_key_id_result.unwrap().unwrap();
|
||||||
|
// Do they own the stream key
|
||||||
|
if stream_key.user_id != auth.0.id {
|
||||||
|
return StatusCode::FORBIDDEN.into_response();
|
||||||
|
}
|
||||||
|
stream_key
|
||||||
|
.into_active_model()
|
||||||
|
.change_label_value(&state.db, new_label.to_string())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
StatusCode::OK.into_response()
|
||||||
|
}
|
||||||
|
|
||||||
async fn catalog_handler(State(state): State<Arc<HttpServer>>) -> impl IntoResponse {
|
async fn catalog_handler(State(state): State<Arc<HttpServer>>) -> impl IntoResponse {
|
||||||
let streams = stream_session::Model::get_all_active_sessions(&state.db)
|
let streams = stream_session::Model::get_all_active_sessions(&state.db)
|
||||||
.await
|
.await
|
||||||
|
|||||||
Reference in New Issue
Block a user