mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Add federation webpage to society; fix dead link on home page
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -3094,6 +3094,7 @@ dependencies = [
|
||||
"actix-files",
|
||||
"actix-web",
|
||||
"actix-ws",
|
||||
"chrono",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"futures",
|
||||
|
||||
72
assets/templates/rc_society/federation.html.hbs
Normal file
72
assets/templates/rc_society/federation.html.hbs
Normal file
@@ -0,0 +1,72 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<!-- Primary Meta Tags -->
|
||||
<title>Federation - Openjam</title>
|
||||
<meta name="title" content="Federation - Openjam" />
|
||||
<meta name="description" content="View federation of this third-party Robocraft servers" />
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://git.ngram.ca/OpenJam/rc-servers" />
|
||||
<meta property="og:title" content="Federation - Openjam" />
|
||||
<meta property="og:description" content="View federation of this third-party Robocraft servers" />
|
||||
<meta property="og:image" content="https://git.ngram.ca/OpenJam/rc-servers/raw/branch/main/assets/robocraft/favicon.jpg" />
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary" />
|
||||
<meta property="twitter:url" content="https://git.ngram.ca/OpenJam/rc-servers" />
|
||||
<meta property="twitter:title" content="Federation - Openjam" />
|
||||
<meta property="twitter:description" content="View federation of this third-party Robocraft servers" />
|
||||
<meta property="twitter:image" content="https://git.ngram.ca/OpenJam/rc-servers/raw/branch/main/assets/robocraft/favicon.jpg" />
|
||||
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||
{{> stylesheet}}
|
||||
</head>
|
||||
<body>
|
||||
<div class="form-stripe">
|
||||
<div class="form-header-right">
|
||||
Welcome {{form.display_name}}! |
|
||||
<a href="/">Home</a> |
|
||||
<a href="/dashboard">Dashboard</a> |
|
||||
<a href="/logout">Sign Out</a>
|
||||
</div>
|
||||
<h1 class="form-banner">Federation Details</h1>
|
||||
{{#if error}}
|
||||
<div class="form-error">
|
||||
<p class="form-error-message">{{error}}</p>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="access-list">
|
||||
{{#each form.instances}}
|
||||
<div class="access-row-box">
|
||||
<h4 class="access-box-title">{{this.domain}}</h4>
|
||||
<div class="box-details">
|
||||
<div class="box-details-key">Database ID</div>
|
||||
<div class="box-details-value">{{this.id}}</div>
|
||||
<div class="box-details-key">Auth Server</div>
|
||||
<div class="box-details-value"><a class="box-details-link" href="{{this.auth}}">{{this.auth}}</a></div>
|
||||
<div class="box-details-key">Society Server</div>
|
||||
<div class="box-details-value"><a class="box-details-link" href="{{this.society}}">{{this.society}}</a></div>
|
||||
<div class="box-details-key">First Seen</div>
|
||||
<div class="box-details-value"><time datetime="{{this.first_used_iso}}">{{this.first_used_iso}}</time></div>
|
||||
<div class="box-details-key">Last Seen</div>
|
||||
<div class="box-details-value"><time datetime="{{this.first_used_iso}}">{{this.first_used_iso}}</time></div>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div class="footer">
|
||||
{{version}}
|
||||
| <a href="{{source_url}}#readme">About</a>
|
||||
| <a href="https://liberapay.com/NGram">Support Me</a>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -46,7 +46,7 @@
|
||||
<div class="form-text-block">
|
||||
<p>
|
||||
This service allows you to manage your account settings, import and export your garage bays, view the server config, and will eventually (not yet) federate with other OpenJam rc-servers instances.
|
||||
You can view other known instances <a href="/federation">here</a>.
|
||||
{{#if form.is_logged_in}}You can view other known instances <a href="/federation">here</a>.{{/if}}
|
||||
This service is intended to have stable public APIs for expanding existing functionality.
|
||||
If you do not want any of this functionality in your instance, simply do not run this service with your instance.
|
||||
</p>
|
||||
|
||||
@@ -11,7 +11,7 @@ mod inventory;
|
||||
pub use inventory::{UnlockedParts, UnlockOverride};
|
||||
|
||||
mod traits;
|
||||
pub use traits::{UserProvider, User, UserToken, UserSlots, UserSlotData, VehicleData, UserAuthInfo, FederatedAuthInfo, UserLoginInfo, UserAuthenticator, FederatedAuthenticator, NewSlotData, UserId, RegistrationInfo, VehicleUploadData, ChatUser, AvatarInfo, GetAvatarInfo, ControlData, ControlType, CustomisationData, GetCustomisationData, SetSanction, SanctionType, LobbyUser, GameDescriptor, PlayerLobbyDescriptor, MultiplayerUser, PlayerScore, MultiplayerError, MultiplayerErrorCode, PlayerDescriptor, GameEventSetter, CurrentGameEvent, AuthError, IntercomUser, FakePlayers, ResolvedVehicle, CommonUser, IntercomListener, UserRole, SocialUser, SocialUserC, CurrencyType, CurrencyOp, MatchRewards, SingleplayerUser, PurchaseResult, FactoryUser, FriendInviteReturn, FriendData, FriendInviteStatus, SocialInfo, ClanData, ClanMember, ClanMemberRank, ClanType, ClanSearchQuery, ClanInviteData, Userless, GameOverrides, WebUser, GarageWebInfo, GarageWebStats, SanctionWebStats, AccountWebStats, SocialWebStats};
|
||||
pub use traits::{UserProvider, User, UserToken, UserSlots, UserSlotData, VehicleData, UserAuthInfo, FederatedAuthInfo, UserLoginInfo, UserAuthenticator, FederatedAuthenticator, NewSlotData, UserId, RegistrationInfo, VehicleUploadData, ChatUser, AvatarInfo, GetAvatarInfo, ControlData, ControlType, CustomisationData, GetCustomisationData, SetSanction, SanctionType, LobbyUser, GameDescriptor, PlayerLobbyDescriptor, MultiplayerUser, PlayerScore, MultiplayerError, MultiplayerErrorCode, PlayerDescriptor, GameEventSetter, CurrentGameEvent, AuthError, IntercomUser, FakePlayers, ResolvedVehicle, CommonUser, IntercomListener, UserRole, SocialUser, SocialUserC, CurrencyType, CurrencyOp, MatchRewards, SingleplayerUser, PurchaseResult, FactoryUser, FriendInviteReturn, FriendData, FriendInviteStatus, SocialInfo, ClanData, ClanMember, ClanMemberRank, ClanType, ClanSearchQuery, ClanInviteData, Userless, GameOverrides, WebUser, GarageWebInfo, GarageWebStats, SanctionWebStats, AccountWebStats, SocialWebStats, FederationWebData, FederationWebDetails};
|
||||
|
||||
pub mod intercom;
|
||||
pub use intercom::generate_token as generate_intercom_token;
|
||||
|
||||
@@ -703,6 +703,7 @@ pub trait WebUser: CommonUser {
|
||||
async fn account_stats(&self) -> Result<AccountWebStats, Box<dyn std::error::Error>>;
|
||||
async fn sanction_stats(&self) -> Result<SanctionWebStats, Box<dyn std::error::Error>>;
|
||||
async fn social_stats(&self) -> Result<SocialWebStats, Box<dyn std::error::Error>>;
|
||||
async fn fedi_info(&self) -> Result<FederationWebData, Box<dyn std::error::Error>>;
|
||||
}
|
||||
|
||||
pub struct GarageWebInfo {
|
||||
@@ -749,6 +750,19 @@ pub struct SocialWebStats {
|
||||
pub chats: Vec<String>,
|
||||
}
|
||||
|
||||
pub struct FederationWebData {
|
||||
pub federations: Vec<FederationWebDetails>,
|
||||
}
|
||||
|
||||
pub struct FederationWebDetails {
|
||||
pub id: i32,
|
||||
pub domain: String,
|
||||
pub auth: String,
|
||||
pub society: String,
|
||||
pub last_used: i64,
|
||||
pub first_used: i64,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait Userless: Send + Sync {
|
||||
async fn lobby_state_listener(&self) -> Result<super::IntercomListener<super::intercom::IntercomLobbyStateMessage>, reqwest_websocket::Error>;
|
||||
|
||||
@@ -202,4 +202,20 @@ impl super::WebUser for super::account_json::UserData {
|
||||
chats: chat_list,
|
||||
})
|
||||
}
|
||||
|
||||
async fn fedi_info(&self) -> Result<super::FederationWebData, Box<dyn std::error::Error>> {
|
||||
let servers = self.db.federations_all().await?;
|
||||
Ok(super::FederationWebData {
|
||||
federations: servers.into_iter()
|
||||
.map(|server| super::FederationWebDetails {
|
||||
id: server.id,
|
||||
domain: server.domain,
|
||||
auth: server.auth,
|
||||
society: server.society,
|
||||
last_used: server.last_used_time,
|
||||
first_used: server.creation_time,
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -943,6 +943,13 @@ impl Database {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn federations_all(&self) -> Result<Vec<crate::schema::federation::Model>, sea_orm::DbErr> {
|
||||
crate::schema::federation::Entity::find()
|
||||
.order_by_asc(crate::schema::federation::Column::Id)
|
||||
.all(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn insert_federation(&self, entity: crate::schema::federation::ActiveModel) -> Result<crate::schema::federation::Model, sea_orm::DbErr> {
|
||||
#[cfg(debug_assertions)]
|
||||
assert!(matches!(entity.id, sea_orm::ActiveValue::NotSet));
|
||||
|
||||
@@ -104,6 +104,7 @@ async fn main() -> std::io::Result<()> {
|
||||
.service(web::user_federation::post_add)
|
||||
.service(web::user_federation::post_off)
|
||||
.service(web::user_federation::post_on)
|
||||
.service(web::federation::get)
|
||||
.service(api::config::get)
|
||||
.service(api::urls::get)
|
||||
})
|
||||
|
||||
@@ -98,7 +98,6 @@ pub async fn dashboard_impl(handlebars_ref: Data<handlebars::Handlebars<'_>>, au
|
||||
match super::try_auth_user(user_opt, auth.as_ref(), &req).await? {
|
||||
super::LoginReturn::AuthFail(resp) => Ok(resp),
|
||||
super::LoginReturn::Success(user) => {
|
||||
// TODO
|
||||
log::debug!("Rendering user's dashboard");
|
||||
let creation_time = user.creation();
|
||||
let creation_time_chrono = chrono::DateTime::<chrono::Utc>::from_timestamp_secs(creation_time).unwrap_or_default();
|
||||
|
||||
85
rc_society/src/web/federation.rs
Normal file
85
rc_society/src/web/federation.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
use actix_web::{get, web::Data, Responder, HttpRequest};
|
||||
use actix_identity::Identity;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use crate::web::{LoginReturn, try_auth_user, render_ok, render_err};
|
||||
|
||||
const FORM_NAME: &str = "federation";
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct RenderData {
|
||||
display_name: String,
|
||||
public_id: String,
|
||||
instances: Vec<FederatedServer>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct FederatedServer {
|
||||
id: i32,
|
||||
domain: String,
|
||||
auth: String,
|
||||
society: String,
|
||||
last_used_unix: i64,
|
||||
last_used_iso: String,
|
||||
first_used_unix: i64,
|
||||
first_used_iso: String,
|
||||
}
|
||||
|
||||
#[get("/federation")]
|
||||
pub async fn get(handlebars_ref: Data<handlebars::Handlebars<'_>>, auth: Data<Box<oj_rc_core::UserImpl>>, user_opt: Option<Identity>, req: HttpRequest) -> Result<impl Responder, actix_web::error::Error> {
|
||||
match try_auth_user(user_opt, auth.as_ref(), &req).await? {
|
||||
LoginReturn::AuthFail(resp) => Ok(resp),
|
||||
LoginReturn::Success(user) => {
|
||||
let fedi_info = match build_fedi_info(user.as_ref()).await {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
let html = render_err(
|
||||
RenderData {
|
||||
display_name: user.display_name().to_owned(),
|
||||
public_id: user.public_id().to_owned(),
|
||||
instances: Vec::default(),
|
||||
},
|
||||
e.to_string(),
|
||||
handlebars_ref.as_ref(),
|
||||
FORM_NAME,
|
||||
);
|
||||
return Ok(
|
||||
html
|
||||
.respond_to(&req)
|
||||
.map_into_boxed_body()
|
||||
);
|
||||
},
|
||||
};
|
||||
let html = render_ok(
|
||||
RenderData {
|
||||
display_name: user.display_name().to_owned(),
|
||||
public_id: user.public_id().to_owned(),
|
||||
instances: fedi_info,
|
||||
},
|
||||
handlebars_ref.as_ref(),
|
||||
FORM_NAME,
|
||||
);
|
||||
Ok(
|
||||
html
|
||||
.respond_to(&req)
|
||||
.map_into_boxed_body()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn build_fedi_info(user: &dyn oj_rc_core::persist::user::WebUser) -> Result<Vec<FederatedServer>, Box<dyn std::error::Error>> {
|
||||
let info = user.fedi_info().await?;
|
||||
Ok(info.federations.into_iter()
|
||||
.map(|instance| FederatedServer {
|
||||
id: instance.id,
|
||||
domain: instance.domain,
|
||||
auth: instance.auth,
|
||||
society: instance.society,
|
||||
last_used_unix: instance.last_used,
|
||||
last_used_iso: chrono::DateTime::<chrono::Utc>::from_timestamp_secs(instance.last_used).unwrap_or_default().to_rfc3339(),
|
||||
first_used_unix: instance.first_used,
|
||||
first_used_iso: chrono::DateTime::<chrono::Utc>::from_timestamp_secs(instance.first_used).unwrap_or_default().to_rfc3339(),
|
||||
}).collect()
|
||||
)
|
||||
}
|
||||
@@ -5,6 +5,7 @@ pub mod index;
|
||||
pub mod garage;
|
||||
pub mod user_federation;
|
||||
pub mod logout;
|
||||
pub mod federation;
|
||||
|
||||
use serde::Serialize;
|
||||
use actix_web::{web::{Html, Redirect}, Responder};
|
||||
|
||||
Reference in New Issue
Block a user