Skip to content

Commit

Permalink
Merge branch 'main' into bug-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
Geometrically authored Jan 9, 2025
2 parents 6ffc101 + 0409fce commit 5bdd7fb
Show file tree
Hide file tree
Showing 11 changed files with 207 additions and 43 deletions.
8 changes: 4 additions & 4 deletions apps/frontend/src/components/ui/AdPlaceholder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ import { ChevronRightIcon } from "@modrinth/assets";
useHead({
script: [
{
// Clean.io
src: "https://cadmus.script.ac/d14pdm1b7fi5kh/script.js",
},
// {
// // Clean.io
// src: "https://cadmus.script.ac/d14pdm1b7fi5kh/script.js",
// },
{
// Aditude
src: "https://dn0qt3r0xannq.cloudfront.net/modrinth-7JfmkEIXEp/modrinth-longform/prebid-load.js",
Expand Down
12 changes: 10 additions & 2 deletions apps/frontend/src/components/ui/servers/ServerListing.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,15 @@
Your server's hardware is currently being upgraded and will be back online shortly.
</div>
<div
v-else-if="status === 'suspended'"
v-if="status === 'suspended' && suspension_reason === 'support'"
class="relative -mt-4 flex w-full flex-row items-center gap-2 rounded-b-3xl bg-bg-blue p-4 text-sm font-bold text-contrast"
>
<HammerIcon />
You recently requested support for your server and we are actively working on it. It will be
back online shortly.
</div>
<div
v-else-if="status === 'suspended' && suspension_reason !== 'upgrading'"
class="relative -mt-4 flex w-full flex-row items-center gap-2 rounded-b-3xl bg-bg-red p-4 text-sm font-bold text-contrast"
>
<UiServersIconsPanelErrorIcon class="!size-5" />
Expand All @@ -72,7 +80,7 @@
</template>

<script setup lang="ts">
import { ChevronRightIcon, LockIcon } from "@modrinth/assets";
import { ChevronRightIcon, HammerIcon, LockIcon } from "@modrinth/assets";
import type { Project, Server } from "~/types/servers";
const props = defineProps<Partial<Server>>();
Expand Down
21 changes: 15 additions & 6 deletions apps/frontend/src/composables/pyroServers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ async function PyroFetch<T>(path: string, options: PyroFetchOptions = {}): Promi
});
return response;
} catch (error) {
console.error("[PYROSERVERS]:", error);
console.error("[PyroServers/PyroFetch]:", error);
if (error instanceof FetchError) {
const statusCode = error.response?.status;
const statusText = error.response?.statusText || "Unknown error";
const statusText = error.response?.statusText || "[no status text available]";
const errorMessages: { [key: number]: string } = {
400: "Bad Request",
401: "Unauthorized",
Expand All @@ -80,15 +80,16 @@ async function PyroFetch<T>(path: string, options: PyroFetchOptions = {}): Promi
429: "Too Many Requests",
500: "Internal Server Error",
502: "Bad Gateway",
503: "Service Unavailable",
};
const message =
statusCode && statusCode in errorMessages
? errorMessages[statusCode]
: `HTTP Error: ${statusCode || "unknown"} ${statusText}`;
throw new PyroFetchError(`[PYROSERVERS][PYRO] ${message}`, statusCode, error);
: `HTTP Error: ${statusCode || "[unhandled status code]"} ${statusText}`;
throw new PyroFetchError(`[PyroServers/PyroFetch] ${message}`, statusCode, error);
}
throw new PyroFetchError(
"[PYROSERVERS][PYRO] An unexpected error occurred during the fetch operation.",
"[PyroServers/PyroFetch] An unexpected error occurred during the fetch operation.",
undefined,
error as Error,
);
Expand Down Expand Up @@ -168,7 +169,15 @@ interface General {
backup_quota: number;
used_backup_quota: number;
status: string;
suspension_reason: string;
suspension_reason:
| "moderated"
| "paymentfailed"
| "cancelled"
| "other"
| "transferring"
| "upgrading"
| "support"
| (string & {});
loader: string;
loader_version: string;
mc_version: string;
Expand Down
74 changes: 73 additions & 1 deletion apps/frontend/src/pages/servers/manage/[id].vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,26 @@
</div>
</div>
<div
v-else-if="serverData?.status === 'suspended'"
v-if="serverData?.status === 'suspended' && serverData.suspension_reason === 'support'"
class="flex min-h-[calc(100vh-4rem)] items-center justify-center text-contrast"
>
<div class="flex max-w-lg flex-col items-center rounded-3xl bg-bg-raised p-6 shadow-xl">
<div class="flex flex-col items-center text-center">
<div class="flex flex-col items-center gap-4">
<div class="grid place-content-center rounded-full bg-bg-blue p-4">
<TransferIcon class="size-12 text-blue" />
</div>
<h1 class="m-0 mb-2 w-fit text-4xl font-bold">We're working on your server</h1>
</div>
<p class="text-lg text-secondary">
You recently contacted Modrinth Support, and we're actively working on your server. It
will be back online shortly.
</p>
</div>
</div>
</div>
<div
v-else-if="serverData?.status === 'suspended' && serverData.suspension_reason !== 'upgrading'"
class="flex min-h-[calc(100vh-4rem)] items-center justify-center text-contrast"
>
<div class="flex max-w-lg flex-col items-center rounded-3xl bg-bg-raised p-6 shadow-xl">
Expand Down Expand Up @@ -69,6 +88,58 @@
</ButtonStyled>
</div>
</div>
<div
v-else-if="server.error && server.error.message.includes('Service Unavailable')"
class="flex min-h-[calc(100vh-4rem)] items-center justify-center text-contrast"
>
<div class="flex max-w-lg flex-col items-center rounded-3xl bg-bg-raised p-6 shadow-xl">
<div class="flex flex-col items-center text-center">
<div class="flex flex-col items-center gap-4">
<div class="grid place-content-center rounded-full bg-bg-red p-4">
<PanelErrorIcon class="size-12 text-red" />
</div>
<h1 class="m-0 mb-4 w-fit text-4xl font-bold">Server Node Unavailable</h1>
</div>
<p class="m-0 mb-4 leading-[170%] text-secondary">
Your server's node, where your Modrinth Server is physically hosted, is experiencing
issues. We are working with our datacenter to resolve the issue as quickly as possible.
</p>
<p class="m-0 mb-4 leading-[170%] text-secondary">
Your data is safe and will not be lost, and your server will be back online as soon as
the issue is resolved.
</p>
<p class="m-0 mb-4 leading-[170%] text-secondary">
For updates, please join the Modrinth Discord or contact Modrinth Support via the chat
bubble in the bottom right corner and we'll be happy to help.
</p>

<div class="flex flex-col gap-2">
<UiCopyCode :text="'Server ID: ' + server.serverId" />
<UiCopyCode :text="'Node: ' + server.general?.datacenter" />
</div>
</div>
<ButtonStyled
size="large"
color="standard"
@click="
() =>
navigateTo('https://discord.modrinth.com', {
external: true,
})
"
>
<button class="mt-6 !w-full">Join Modrinth Discord</button>
</ButtonStyled>
<ButtonStyled
:disabled="formattedTime !== '00'"
size="large"
color="standard"
@click="() => reloadNuxtApp()"
>
<button class="mt-3 !w-full">Reload</button>
</ButtonStyled>
</div>
</div>
<div
v-else-if="server.error"
class="flex min-h-[calc(100vh-4rem)] items-center justify-center text-contrast"
Expand Down Expand Up @@ -324,6 +395,7 @@ import { Intercom, shutdown } from "@intercom/messenger-js-sdk";
import { reloadNuxtApp } from "#app";
import type { ServerState, Stats, WSEvent, WSInstallationResultEvent } from "~/types/servers";
import { usePyroConsole } from "~/store/console.ts";
import PanelErrorIcon from "~/components/ui/servers/icons/PanelErrorIcon.vue";
const socket = ref<WebSocket | null>(null);
const isReconnecting = ref(false);
Expand Down
5 changes: 4 additions & 1 deletion apps/labrinth/.env
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,7 @@ ADITUDE_API_KEY=none
PYRO_API_KEY=none

BREX_API_URL=https://platform.brexapis.com/v2/
BREX_API_KEY=none
BREX_API_KEY=none

DELPHI_URL=none
DELPHI_SLACK_WEBHOOK=none
3 changes: 3 additions & 0 deletions apps/labrinth/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,10 @@ pub fn check_env_vars() -> bool {

failed |= check_var::<String>("PYRO_API_KEY");

failed |= check_var::<String>("BREX_API_URL");
failed |= check_var::<String>("BREX_API_KEY");

failed |= check_var::<String>("DELPHI_URL");

failed
}
2 changes: 1 addition & 1 deletion apps/labrinth/src/queue/moderation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use std::io::{Cursor, Read};
use std::time::Duration;
use zip::ZipArchive;

const AUTOMOD_ID: i64 = 0;
pub const AUTOMOD_ID: i64 = 0;

pub struct ModerationMessages {
pub messages: Vec<ModerationMessage>,
Expand Down
79 changes: 78 additions & 1 deletion apps/labrinth/src/routes/internal/admin.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use crate::auth::validate::get_user_record_from_bearer_token;
use crate::database::models::thread_item::ThreadMessageBuilder;
use crate::database::redis::RedisPool;
use crate::models::analytics::Download;
use crate::models::ids::ProjectId;
use crate::models::pats::Scopes;
use crate::models::threads::MessageBody;
use crate::queue::analytics::AnalyticsQueue;
use crate::queue::maxmind::MaxMindIndexer;
use crate::queue::moderation::AUTOMOD_ID;
use crate::queue::payouts::PayoutsQueue;
use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
Expand All @@ -17,13 +20,15 @@ use sqlx::PgPool;
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::sync::Arc;
use log::info;

pub fn config(cfg: &mut web::ServiceConfig) {
cfg.service(
web::scope("admin")
.service(count_download)
.service(force_reindex)
.service(get_balances),
.service(get_balances)
.service(delphi_result_ingest),
);
}

Expand Down Expand Up @@ -178,3 +183,75 @@ pub async fn get_balances(
"tremendous": tremendous,
})))
}

#[derive(Deserialize)]
pub struct DelphiIngest {
pub url: String,
pub project_id: crate::models::ids::ProjectId,
pub version_id: crate::models::ids::VersionId,
pub issues: Vec<String>,
}

#[post("/_delphi", guard = "admin_key_guard")]
pub async fn delphi_result_ingest(
pool: web::Data<PgPool>,
redis: web::Data<RedisPool>,
body: web::Json<DelphiIngest>,
) -> Result<HttpResponse, ApiError> {
if body.issues.is_empty() {
info!("No issues found for file {}", body.url);
return Ok(HttpResponse::NoContent().finish());
}

let webhook_url = dotenvy::var("DELPHI_SLACK_WEBHOOK")?;

let project = crate::database::models::Project::get_id(
body.project_id.into(),
&**pool,
&redis,
)
.await?
.ok_or_else(|| {
ApiError::InvalidInput(format!(
"Project {} does not exist",
body.project_id
))
})?;

crate::util::webhook::send_slack_webhook(
body.project_id,
&pool,
&redis,
webhook_url,
Some(format!(
"Suspicious traces found at {}. Traces: {}",
body.url,
body.issues.join(", ")
)),
)
.await
.ok();

let mut transaction = pool.begin().await?;
ThreadMessageBuilder {
author_id: Some(crate::database::models::UserId(AUTOMOD_ID)),
body: MessageBody::Text {
body: format!(
"WSR; Suspicious traces found for version_id {}. Traces: {}",
body.version_id,
body.issues.join(", ")
),
private: true,
replying_to: None,
associated_images: vec![],
},
thread_id: project.thread_id,
hide_identity: false,
}
.insert(&mut transaction)
.await?;

transaction.commit().await?;

Ok(HttpResponse::NoContent().finish())
}
5 changes: 0 additions & 5 deletions apps/labrinth/src/routes/v2/projects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,6 @@ pub async fn project_search(
let facets: Option<Vec<Vec<String>>> = if let Some(facets) = info.facets {
let facets = serde_json::from_str::<Vec<Vec<String>>>(&facets)?;

// These loaders specifically used to be combined with 'mod' to be a plugin, but now
// they are their own loader type. We will convert 'mod' to 'mod' OR 'plugin'
// as it essentially was before.
let facets = v2_reroute::convert_plugin_loader_facets_v3(facets);

Some(
facets
.into_iter()
Expand Down
22 changes: 0 additions & 22 deletions apps/labrinth/src/routes/v2_reroute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,28 +190,6 @@ pub fn convert_side_types_v3(
fields
}

// Converts plugin loaders from v2 to v3, for search facets
// Within every 1st and 2nd level (the ones allowed in v2), we convert every instance of:
// "project_type:mod" to "project_type:plugin" OR "project_type:mod"
pub fn convert_plugin_loader_facets_v3(
facets: Vec<Vec<String>>,
) -> Vec<Vec<String>> {
facets
.into_iter()
.map(|inner_facets| {
if inner_facets == ["project_type:mod"] {
vec![
"project_type:plugin".to_string(),
"project_type:datapack".to_string(),
"project_type:mod".to_string(),
]
} else {
inner_facets
}
})
.collect::<Vec<_>>()
}

// Convert search facets from V3 back to v2
// this is not lossless. (See tests)
pub fn convert_side_types_v2(
Expand Down
19 changes: 19 additions & 0 deletions apps/labrinth/src/routes/v3/version_creation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use actix_web::{web, HttpRequest, HttpResponse};
use chrono::Utc;
use futures::stream::StreamExt;
use itertools::Itertools;
use log::error;
use serde::{Deserialize, Serialize};
use sqlx::postgres::PgPool;
use std::collections::{HashMap, HashSet};
Expand Down Expand Up @@ -980,6 +981,24 @@ pub async fn upload_file(
}
}

let url = format!("{cdn_url}/{file_path_encode}");

let client = reqwest::Client::new();
let delphi_url = dotenvy::var("DELPHI_URL")?;
let res = client
.post(delphi_url)
.json(&serde_json::json!({
"url": url,
"project_id": project_id,
"version_id": version_id,
}))
.send()
.await?;

if !res.status().is_success() {
error!("Failed to upload file to Delphi: {url}");
}

version_files.push(VersionFileBuilder {
filename: file_name.to_string(),
url: format!("{cdn_url}/{file_path_encode}"),
Expand Down

0 comments on commit 5bdd7fb

Please sign in to comment.