add: patch method on stream key
This commit is contained in:
Generated
+1
@@ -2879,6 +2879,7 @@ dependencies = [
|
||||
"migration",
|
||||
"opus",
|
||||
"rand 0.10.1",
|
||||
"regex",
|
||||
"rml_rtmp",
|
||||
"rubato",
|
||||
"sea-orm",
|
||||
|
||||
@@ -79,3 +79,14 @@ impl Entity {
|
||||
.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"
|
||||
rubato = "3.0.0"
|
||||
chrono = "0.4.45"
|
||||
regex = "1"
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
use std::{
|
||||
net::SocketAddr,
|
||||
sync::{
|
||||
Arc,
|
||||
Arc, LazyLock,
|
||||
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::{
|
||||
Json, Router,
|
||||
body::{Body, Bytes},
|
||||
@@ -20,7 +30,9 @@ use axum::{
|
||||
};
|
||||
use chrono::{DateTime, Utc};
|
||||
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 tokio::{
|
||||
net::TcpListener,
|
||||
@@ -83,7 +95,9 @@ impl HttpServer {
|
||||
.route("/api/user", post(create_user_handler))
|
||||
.route(
|
||||
"/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/whip", post(handle_whip_injest))
|
||||
@@ -112,6 +126,48 @@ struct StreamListing {
|
||||
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 {
|
||||
let streams = stream_session::Model::get_all_active_sessions(&state.db)
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user