mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-27 12:10:08 -04:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d04276db2f |
-36
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT DISTINCT\n subscription_namespace as `subscription_namespace: enums::common::payments_namespace::PaymentsNamespace`,\n maybe_stripe_customer_id as `stripe_customer_id!`\n\nFROM user_subscriptions\n\nWHERE\n user_token = ?\n AND maybe_stripe_customer_id IS NOT NULL\n AND deleted_at IS NULL\nORDER BY subscription_namespace ASC, maybe_stripe_customer_id ASC\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "subscription_namespace: enums::common::payments_namespace::PaymentsNamespace",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "stripe_customer_id!",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "MULTIPLE_KEY | BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "516db34b6a642a2f7d7107f186905a79ad694c3c86f3078efc77bcaae7f39f3d"
|
||||
}
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n user_token as `user_token: tokens::tokens::users::UserToken`,\n payments_namespace as `payments_namespace: enums::common::payments_namespace::PaymentsNamespace`,\n stripe_customer_id\n\nFROM user_stripe_customer_links\n\nWHERE user_token = ?\nORDER BY id ASC\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "payments_namespace: enums::common::payments_namespace::PaymentsNamespace",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "stripe_customer_id",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "ffb5717340f21f21693bfcade201bc055fb3fb8a26da8d0574e3de44b033586c"
|
||||
}
|
||||
@@ -2,6 +2,5 @@ pub mod alerts;
|
||||
pub mod jobs;
|
||||
pub mod user;
|
||||
pub mod user_referrals;
|
||||
pub mod user_stripe_data;
|
||||
pub mod wallet_ledger_entries;
|
||||
pub mod wallets;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
pub mod moderator_get_user_stripe_customer_ids;
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
use enums::common::payments_namespace::PaymentsNamespace;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use tokens::tokens::users::UserToken;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
pub const MODERATOR_GET_USER_STRIPE_CUSTOMER_IDS_PATH: &str =
|
||||
"/v1/moderation/user_stripe_data/{user_token}/customer_ids";
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct ModeratorGetUserStripeCustomerIdsPathInfo {
|
||||
pub user_token: UserToken,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct ModeratorGetUserStripeCustomerIdsResponse {
|
||||
pub success: bool,
|
||||
|
||||
/// All stripe customer ids we have on file for the user, across payments
|
||||
/// namespaces. A user may have zero or several: a customer link and/or
|
||||
/// subscriptions per namespace (eg. artcraft), plus legacy fakeyou
|
||||
/// subscriptions. The same customer id can appear once per source.
|
||||
pub customer_ids: Vec<ModeratorUserStripeCustomerIdEntry>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct ModeratorUserStripeCustomerIdEntry {
|
||||
pub stripe_customer_id: String,
|
||||
pub payments_namespace: PaymentsNamespace,
|
||||
pub source: ModeratorStripeCustomerIdSource,
|
||||
|
||||
/// Link to the customer in the Stripe dashboard for the namespace's account.
|
||||
pub stripe_dashboard_url: String,
|
||||
}
|
||||
|
||||
/// Which table the customer id was found in.
|
||||
#[derive(Serialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ModeratorStripeCustomerIdSource {
|
||||
/// From the `user_stripe_customer_links` table (1:1 per namespace).
|
||||
CustomerLink,
|
||||
/// From the user's rows in the `user_subscriptions` table.
|
||||
Subscription,
|
||||
}
|
||||
-18
File diff suppressed because one or more lines are too long
-25
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"type": "json",
|
||||
"current_status": "completed",
|
||||
"percentage_complete": 100,
|
||||
"job_id": "c1bed796-3f05-4716-8ef0-a4d4900dfc6e",
|
||||
"elapsed": null,
|
||||
"prompt": "a dog typing on a keyboard",
|
||||
"confirmation": "Drew a dog typing",
|
||||
"full_prompt": "a dog typing on a keyboard",
|
||||
"flags": null,
|
||||
"is_alteration": false,
|
||||
"section_id": 0,
|
||||
"input_type": "text",
|
||||
"request_id": "fc39cefd-fcf9-4775-b490-7e17ce670060",
|
||||
"asr_transcript": null,
|
||||
"asr_accepted": null,
|
||||
"seed": null,
|
||||
"image_reference": null,
|
||||
"is_image_edit": null,
|
||||
"moderated": false,
|
||||
"r_rated": false,
|
||||
"order": 1,
|
||||
"model_name": "imagine_h_1",
|
||||
"image_id": "78b3e6ef-defc-41a6-a9ac-b7a370d26ce5"
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"type": "json",
|
||||
"current_status": "start_stage",
|
||||
"percentage_complete": 0,
|
||||
"job_id": "57baeffe-d5cf-483b-a5bb-7794899f905c",
|
||||
"elapsed": null,
|
||||
"prompt": "a dog typing on a keyboard",
|
||||
"confirmation": "Drew a dog typing",
|
||||
"full_prompt": "a dog typing on a keyboard",
|
||||
"flags": null,
|
||||
"is_alteration": true,
|
||||
"section_id": 0,
|
||||
"input_type": "text",
|
||||
"request_id": "fc39cefd-fcf9-4775-b490-7e17ce670060",
|
||||
"asr_transcript": null,
|
||||
"asr_accepted": null,
|
||||
"seed": null,
|
||||
"image_reference": null,
|
||||
"is_image_edit": null,
|
||||
"moderated": false,
|
||||
"r_rated": null,
|
||||
"order": 7,
|
||||
"model_name": "imagine_h_1",
|
||||
"image_id": null
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"type": "conversation.item.create",
|
||||
"timestamp": 1761010203630,
|
||||
"item": {
|
||||
"type": "message",
|
||||
"content": [
|
||||
{
|
||||
"requestId": "fc39cefd-fcf9-4775-b490-7e17ce670060",
|
||||
"text": "a dog typing on a keyboard",
|
||||
"type": "input_text",
|
||||
"properties": {
|
||||
"section_count": 0,
|
||||
"is_kids_mode": false,
|
||||
"enable_nsfw": true,
|
||||
"skip_upsampler": false,
|
||||
"is_initial": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"type": "other_type",
|
||||
"foo": "bar"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"type":"json","current_status":"start_stage","percentage_complete":0.0,"job_id":"0080eaac-f7f7-4369-90a2-346491939c1b","elapsed":null,"prompt":"a dog riding a motorcycle","confirmation":"Drew a dog riding a motorcycle","full_prompt":"a dog riding a motorcycle","flags":null,"is_alteration":false,"section_id":0,"input_type":"text","request_id":"bbc15402-3257-4415-922e-b156c151f3c2","asr_transcript":null,"asr_accepted":null,"seed":null,"image_reference":null,"is_image_edit":null,"moderated":false,"r_rated":null,"order":0,"model_name":"imagine_h_1","image_id":null}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"type": "json",
|
||||
"current_status": "start_stage",
|
||||
"percentage_complete": 0,
|
||||
"job_id": "0080eaac-f7f7-4369-90a2-346491939c1b",
|
||||
"elapsed": null,
|
||||
"prompt": "a dog riding a motorcycle",
|
||||
"confirmation": "Drew a dog riding a motorcycle",
|
||||
"full_prompt": "a dog riding a motorcycle",
|
||||
"flags": null,
|
||||
"is_alteration": false,
|
||||
"section_id": 0,
|
||||
"input_type": "text",
|
||||
"request_id": "bbc15402-3257-4415-922e-b156c151f3c2",
|
||||
"asr_transcript": null,
|
||||
"asr_accepted": null,
|
||||
"seed": null,
|
||||
"image_reference": null,
|
||||
"is_image_edit": null,
|
||||
"moderated": false,
|
||||
"r_rated": null,
|
||||
"order": 0,
|
||||
"model_name": "imagine_h_1",
|
||||
"image_id": null
|
||||
}
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::MySql;
|
||||
|
||||
use enums::common::payments_namespace::PaymentsNamespace;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::queries::users::user_stripe_customer_links::find_user_stripe_customer_link::UserStripeCustomerLink;
|
||||
|
||||
/// List every stripe customer link for a user, across all payments namespaces.
|
||||
/// Users have at most one link per namespace.
|
||||
pub async fn list_user_stripe_customer_links_for_user(
|
||||
user_token: &UserToken,
|
||||
connection: &mut PoolConnection<MySql>,
|
||||
) -> Result<Vec<UserStripeCustomerLink>, sqlx::Error> {
|
||||
let records = sqlx::query_as!(
|
||||
RawUserStripeCustomerLink,
|
||||
r#"
|
||||
SELECT
|
||||
user_token as `user_token: tokens::tokens::users::UserToken`,
|
||||
payments_namespace as `payments_namespace: enums::common::payments_namespace::PaymentsNamespace`,
|
||||
stripe_customer_id
|
||||
|
||||
FROM user_stripe_customer_links
|
||||
|
||||
WHERE user_token = ?
|
||||
ORDER BY id ASC
|
||||
"#,
|
||||
user_token.as_str(),
|
||||
)
|
||||
.fetch_all(&mut **connection)
|
||||
.await?;
|
||||
|
||||
let links = records
|
||||
.into_iter()
|
||||
.map(|record| UserStripeCustomerLink {
|
||||
user_token: record.user_token,
|
||||
payments_namespace: record.payments_namespace,
|
||||
stripe_customer_id: record.stripe_customer_id,
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(links)
|
||||
}
|
||||
|
||||
#[derive(sqlx::FromRow)]
|
||||
struct RawUserStripeCustomerLink {
|
||||
user_token: UserToken,
|
||||
payments_namespace: PaymentsNamespace,
|
||||
stripe_customer_id: String,
|
||||
}
|
||||
+1
-2
@@ -1,3 +1,2 @@
|
||||
pub mod find_user_stripe_customer_link;
|
||||
pub mod list_user_stripe_customer_links_for_user;
|
||||
pub mod upsert_user_stripe_customer_link;
|
||||
pub mod upsert_user_stripe_customer_link;
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::MySql;
|
||||
|
||||
use enums::common::payments_namespace::PaymentsNamespace;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
/// A distinct stripe customer id attached to one of the user's subscriptions.
|
||||
pub struct UserSubscriptionStripeCustomerId {
|
||||
pub subscription_namespace: PaymentsNamespace,
|
||||
pub stripe_customer_id: String,
|
||||
}
|
||||
|
||||
/// List the distinct stripe customer ids across all of a user's subscriptions
|
||||
/// (current and historical), across all payments namespaces.
|
||||
pub async fn list_stripe_customer_ids_for_user_subscriptions(
|
||||
user_token: &UserToken,
|
||||
connection: &mut PoolConnection<MySql>,
|
||||
) -> Result<Vec<UserSubscriptionStripeCustomerId>, sqlx::Error> {
|
||||
let records = sqlx::query_as!(
|
||||
UserSubscriptionStripeCustomerId,
|
||||
r#"
|
||||
SELECT DISTINCT
|
||||
subscription_namespace as `subscription_namespace: enums::common::payments_namespace::PaymentsNamespace`,
|
||||
maybe_stripe_customer_id as `stripe_customer_id!`
|
||||
|
||||
FROM user_subscriptions
|
||||
|
||||
WHERE
|
||||
user_token = ?
|
||||
AND maybe_stripe_customer_id IS NOT NULL
|
||||
AND deleted_at IS NULL
|
||||
ORDER BY subscription_namespace ASC, maybe_stripe_customer_id ASC
|
||||
"#,
|
||||
user_token.as_str(),
|
||||
)
|
||||
.fetch_all(&mut **connection)
|
||||
.await?;
|
||||
|
||||
Ok(records)
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
pub mod find_possibly_inactive_first_subscription_for_owner_user;
|
||||
pub mod lookup_users_by_stripe_customer_id;
|
||||
pub mod find_subscription_for_owner_user;
|
||||
pub mod get_user_subscription_by_stripe_subscription_id;
|
||||
pub mod list_active_user_subscriptions;
|
||||
pub mod list_stripe_customer_ids_for_user_subscriptions;
|
||||
pub mod lookup_users_by_stripe_customer_id;
|
||||
pub mod upsert_user_subscription_by_stripe_id;
|
||||
pub mod upsert_user_subscription_with_invoice_paid_status_by_stripe_id;
|
||||
|
||||
+3
-3
@@ -127,7 +127,7 @@ mod tests {
|
||||
{"id":"sub_1LhA3MEU5se17MekeWvmTNyk","automatic_tax":{"enabled":false},
|
||||
"billing_cycle_anchor":1662979188,"cancel_at_period_end":false,
|
||||
"collection_method":"charge_automatically","created":1662979188,"current_period_end":1665571188,
|
||||
"current_period_start":1662979188,"customer":"cus_MQ03py0gWUh0Ox","currency":"usd","default_tax_rates":[],
|
||||
"current_period_start":1662979188,"customer":"cus_MQ03py0gWUh0Ox","default_tax_rates":[],
|
||||
"items":{"data":[{"id":"si_MQ03hadVNfRnaS","created":1662979188,"deleted":false,"metadata":{},
|
||||
"price":{"id":"price_1LeDnKEU5se17MekVr1iYYNf","active":true,"billing_scheme":"per_unit",
|
||||
"created":1662278586,"currency":"usd","deleted":false,"livemode":false,"metadata":{},
|
||||
@@ -172,7 +172,7 @@ mod tests {
|
||||
"cancel_at_period_end":false,"collection_method":"charge_automatically","created":1662948037,
|
||||
"current_period_end":1665540037,"current_period_start":1662948037,
|
||||
"customer":"cus_MPrgIen5Wh6QKG",
|
||||
"default_payment_method":"pm_1Lh1wtEU5se17MekpirKtMJm","currency":"usd","default_tax_rates":[],
|
||||
"default_payment_method":"pm_1Lh1wtEU5se17MekpirKtMJm","default_tax_rates":[],
|
||||
"items":{"data":[{"id":"si_MPrgTAV333Nq7c","created":1662948037,"deleted":false,"metadata":{},
|
||||
"price":{"id":"price_1LeDnKEU5se17MekVr1iYYNf","active":true,"billing_scheme":"per_unit",
|
||||
"created":1662278586,"currency":"usd","deleted":false,"livemode":false,"metadata":{},
|
||||
@@ -216,7 +216,7 @@ mod tests {
|
||||
"billing_cycle_anchor":1662979188,"cancel_at_period_end":false,"canceled_at":1662979740,
|
||||
"collection_method":"charge_automatically","created":1662979188,"current_period_end":1665571188,
|
||||
"current_period_start":1662979188,"customer":"cus_MQ03py0gWUh0Ox",
|
||||
"default_payment_method":"pm_1LhA3LEU5se17MekViNvoYAx","currency":"usd","default_tax_rates":[],
|
||||
"default_payment_method":"pm_1LhA3LEU5se17MekViNvoYAx","default_tax_rates":[],
|
||||
"ended_at":1662979740,"items":{"data":[{"id":"si_MQ03hadVNfRnaS","created":1662979188,
|
||||
"deleted":false,"metadata":{},"price":{"id":"price_1LeDnKEU5se17MekVr1iYYNf","active":true,
|
||||
"billing_scheme":"per_unit","created":1662278586,"currency":"usd","deleted":false,
|
||||
|
||||
+6
-25
@@ -127,11 +127,8 @@ mod tests {
|
||||
{"id":"sub_1LhA3MEU5se17MekeWvmTNyk","automatic_tax":{"enabled":false},
|
||||
"billing_cycle_anchor":1662979188,"cancel_at_period_end":false,
|
||||
"collection_method":"charge_automatically","created":1662979188,"current_period_end":1665571188,
|
||||
"current_period_start":1662979188,"customer":"cus_MQ03py0gWUh0Ox","currency":"usd","default_tax_rates":[],"discounts":[],
|
||||
"invoice_settings":{"issuer":{"type":"self"}},
|
||||
"items":{"data":[{"id":"si_MQ03hadVNfRnaS","created":1662979188,"current_period_end":1665571188,
|
||||
"current_period_start":1662979188,"deleted":false,"discounts":[],
|
||||
"plan":{"id":"price_1LeDnKEU5se17MekVr1iYYNf","object":"plan","active":true,"amount":700,"amount_decimal":"700","billing_scheme":"per_unit","created":1662278586,"currency":"usd","interval":"month","interval_count":1,"livemode":false,"metadata":{},"product":"prod_MMxi2J5y69VPbO","usage_type":"licensed"},"metadata":{},
|
||||
"current_period_start":1662979188,"customer":"cus_MQ03py0gWUh0Ox","default_tax_rates":[],
|
||||
"items":{"data":[{"id":"si_MQ03hadVNfRnaS","created":1662979188,"deleted":false,"metadata":{},
|
||||
"price":{"id":"price_1LeDnKEU5se17MekVr1iYYNf","active":true,"billing_scheme":"per_unit",
|
||||
"created":1662278586,"currency":"usd","deleted":false,"livemode":false,"metadata":{},
|
||||
"product":"prod_MMxi2J5y69VPbO","recurring":{"interval":"month","interval_count":1,
|
||||
@@ -175,11 +172,8 @@ mod tests {
|
||||
"cancel_at_period_end":false,"collection_method":"charge_automatically","created":1662948037,
|
||||
"current_period_end":1665540037,"current_period_start":1662948037,
|
||||
"customer":"cus_MPrgIen5Wh6QKG",
|
||||
"default_payment_method":"pm_1Lh1wtEU5se17MekpirKtMJm","currency":"usd","default_tax_rates":[],"discounts":[],
|
||||
"invoice_settings":{"issuer":{"type":"self"}},
|
||||
"items":{"data":[{"id":"si_MPrgTAV333Nq7c","created":1662948037,"current_period_end":1665540037,
|
||||
"current_period_start":1662948037,"deleted":false,"discounts":[],
|
||||
"plan":{"id":"price_1LeDnKEU5se17MekVr1iYYNf","object":"plan","active":true,"amount":700,"amount_decimal":"700","billing_scheme":"per_unit","created":1662278586,"currency":"usd","interval":"month","interval_count":1,"livemode":false,"metadata":{},"product":"prod_MMxi2J5y69VPbO","usage_type":"licensed"},"metadata":{},
|
||||
"default_payment_method":"pm_1Lh1wtEU5se17MekpirKtMJm","default_tax_rates":[],
|
||||
"items":{"data":[{"id":"si_MPrgTAV333Nq7c","created":1662948037,"deleted":false,"metadata":{},
|
||||
"price":{"id":"price_1LeDnKEU5se17MekVr1iYYNf","active":true,"billing_scheme":"per_unit",
|
||||
"created":1662278586,"currency":"usd","deleted":false,"livemode":false,"metadata":{},
|
||||
"product":"prod_MMxi2J5y69VPbO","recurring":{"interval":"month","interval_count":1,
|
||||
@@ -222,12 +216,9 @@ mod tests {
|
||||
"billing_cycle_anchor":1662979188,"cancel_at_period_end":false,"canceled_at":1662979740,
|
||||
"collection_method":"charge_automatically","created":1662979188,"current_period_end":1665571188,
|
||||
"current_period_start":1662979188,"customer":"cus_MQ03py0gWUh0Ox",
|
||||
"default_payment_method":"pm_1LhA3LEU5se17MekViNvoYAx","currency":"usd","default_tax_rates":[],"discounts":[],
|
||||
"invoice_settings":{"issuer":{"type":"self"}},
|
||||
"default_payment_method":"pm_1LhA3LEU5se17MekViNvoYAx","default_tax_rates":[],
|
||||
"ended_at":1662979740,"items":{"data":[{"id":"si_MQ03hadVNfRnaS","created":1662979188,
|
||||
"current_period_end":1665571188,"current_period_start":1662979188,
|
||||
"deleted":false,"discounts":[],
|
||||
"plan":{"id":"price_1LeDnKEU5se17MekVr1iYYNf","object":"plan","active":true,"amount":700,"amount_decimal":"700","billing_scheme":"per_unit","created":1662278586,"currency":"usd","interval":"month","interval_count":1,"livemode":false,"metadata":{},"product":"prod_MMxi2J5y69VPbO","usage_type":"licensed"},"metadata":{},"price":{"id":"price_1LeDnKEU5se17MekVr1iYYNf","active":true,
|
||||
"deleted":false,"metadata":{},"price":{"id":"price_1LeDnKEU5se17MekVr1iYYNf","active":true,
|
||||
"billing_scheme":"per_unit","created":1662278586,"currency":"usd","deleted":false,
|
||||
"livemode":false,"metadata":{},"product":"prod_MMxi2J5y69VPbO",
|
||||
"recurring":{"interval":"month","interval_count":1,"usage_type":"licensed"},
|
||||
@@ -292,14 +283,7 @@ mod tests {
|
||||
],
|
||||
"description": null,
|
||||
"discount": null,
|
||||
"discounts": [
|
||||
],
|
||||
"ended_at": null,
|
||||
"invoice_settings": {
|
||||
"issuer": {
|
||||
"type": "self"
|
||||
}
|
||||
},
|
||||
"items": {
|
||||
"object": "list",
|
||||
"data": [
|
||||
@@ -308,9 +292,6 @@ mod tests {
|
||||
"object": "subscription_item",
|
||||
"billing_thresholds": null,
|
||||
"created": 1663430298,
|
||||
"current_period_end": 1666022298,
|
||||
"current_period_start": 1663430298,
|
||||
"discounts": [],
|
||||
"metadata": {
|
||||
},
|
||||
"plan": {
|
||||
|
||||
@@ -2,8 +2,6 @@ use stripe::Client;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ArtcraftStripeConfig {
|
||||
/// The Stripe account id (eg. "acct_..."), used to build dashboard links.
|
||||
pub stripe_account_id: String,
|
||||
pub secret_key: String,
|
||||
pub secret_webhook_signing_key: String,
|
||||
pub checkout_success_url: String,
|
||||
@@ -13,8 +11,6 @@ pub struct ArtcraftStripeConfig {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ArtcraftStripeConfigWithClient {
|
||||
/// The Stripe account id (eg. "acct_..."), used to build dashboard links.
|
||||
pub stripe_account_id: String,
|
||||
pub secret_key: String,
|
||||
pub secret_webhook_signing_key: String,
|
||||
pub checkout_success_url: String,
|
||||
@@ -26,7 +22,6 @@ pub struct ArtcraftStripeConfigWithClient {
|
||||
impl ArtcraftStripeConfig {
|
||||
pub fn to_config_with_client(&self) -> ArtcraftStripeConfigWithClient {
|
||||
ArtcraftStripeConfigWithClient {
|
||||
stripe_account_id: self.stripe_account_id.clone(),
|
||||
secret_key: self.secret_key.clone(),
|
||||
secret_webhook_signing_key: self.secret_webhook_signing_key.clone(),
|
||||
checkout_success_url: self.checkout_success_url.clone(),
|
||||
|
||||
@@ -117,7 +117,6 @@ use artcraft_api_defs::folders::media_files::*;
|
||||
use artcraft_api_defs::folders::subfolder::*;
|
||||
use artcraft_api_defs::moderation::user_referrals::list_global_user_referrals::*;
|
||||
use artcraft_api_defs::moderation::user_referrals::list_user_referrals_for_user::*;
|
||||
use artcraft_api_defs::moderation::user_stripe_data::moderator_get_user_stripe_customer_ids::*;
|
||||
use crate::http_server::endpoints::moderation::user_sessions::moderator_list_user_session_impersonation_requests_for_user_handler::*;
|
||||
use crate::http_server::endpoints::moderation::user_sessions::moderator_list_user_session_impersonation_requests_handler::*;
|
||||
use crate::http_server::endpoints::moderation::user_sessions::moderator_user_session_impersonation_request_handler::*;
|
||||
@@ -559,7 +558,6 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux
|
||||
crate::http_server::endpoints::moderation::user_bans::moderation_ban_user_handler::moderation_ban_user_handler,
|
||||
crate::http_server::endpoints::moderation::user_emails::moderator_change_user_email_handler::moderator_change_user_email_handler,
|
||||
crate::http_server::endpoints::moderation::user_emails::moderator_list_email_address_changes_for_user_handler::moderator_list_email_address_changes_for_user_handler,
|
||||
crate::http_server::endpoints::moderation::user_stripe_data::moderator_get_user_stripe_customer_ids_handler::moderator_get_user_stripe_customer_ids_handler,
|
||||
|
||||
// Folders
|
||||
crate::http_server::endpoints::folders::folder::create_folder_handler::create_folder_handler,
|
||||
@@ -818,10 +816,6 @@ use crate::http_server::endpoints::media_files::list::list_batch_generated_redux
|
||||
ModeratorGetWalletLedgerEntryPathInfo,
|
||||
ModeratorGetWalletLedgerEntryResponse,
|
||||
ModeratorGetWalletLedgerEntryDetails,
|
||||
ModeratorGetUserStripeCustomerIdsPathInfo,
|
||||
ModeratorGetUserStripeCustomerIdsResponse,
|
||||
ModeratorUserStripeCustomerIdEntry,
|
||||
ModeratorStripeCustomerIdSource,
|
||||
GptImage1EditImageRequest,
|
||||
GptImage1EditImageImageSize,
|
||||
GptImage1EditImageNumImages,
|
||||
|
||||
@@ -10,6 +10,5 @@ pub mod user_emails;
|
||||
pub mod user_feature_flags;
|
||||
pub mod user_referrals;
|
||||
pub mod user_sessions;
|
||||
pub mod user_stripe_data;
|
||||
pub mod wallet_ledger_entries;
|
||||
pub mod wallets;
|
||||
|
||||
-1
@@ -1 +0,0 @@
|
||||
pub mod moderator_get_user_stripe_customer_ids_handler;
|
||||
-101
@@ -1,101 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use actix_web::web::{Json, Path};
|
||||
use actix_web::{web, HttpRequest};
|
||||
use log::warn;
|
||||
|
||||
use artcraft_api_defs::moderation::user_stripe_data::moderator_get_user_stripe_customer_ids::{
|
||||
ModeratorGetUserStripeCustomerIdsPathInfo,
|
||||
ModeratorGetUserStripeCustomerIdsResponse,
|
||||
ModeratorStripeCustomerIdSource,
|
||||
ModeratorUserStripeCustomerIdEntry,
|
||||
};
|
||||
use mysql_queries::queries::users::user_stripe_customer_links::list_user_stripe_customer_links_for_user::list_user_stripe_customer_links_for_user;
|
||||
use enums::common::payments_namespace::PaymentsNamespace;
|
||||
use mysql_queries::queries::users::user_subscriptions::list_stripe_customer_ids_for_user_subscriptions::list_stripe_customer_ids_for_user_subscriptions;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::http_server::common_responses::common_web_error::CommonWebError;
|
||||
use crate::http_server::web_utils::user_session::require_moderator::{require_moderator, UseDatabase};
|
||||
use crate::state::server_state::ServerState;
|
||||
|
||||
/// Get all stripe customer ids on file for a user (moderation)
|
||||
#[utoipa::path(
|
||||
get,
|
||||
tag = "Moderation",
|
||||
path = "/v1/moderation/user_stripe_data/{user_token}/customer_ids",
|
||||
responses(
|
||||
(status = 200, description = "Success", body = ModeratorGetUserStripeCustomerIdsResponse),
|
||||
(status = 401, description = "Unauthorized"),
|
||||
(status = 500, description = "Server error"),
|
||||
),
|
||||
params(
|
||||
("user_token" = UserToken, Path, description = "User token to look up"),
|
||||
)
|
||||
)]
|
||||
pub async fn moderator_get_user_stripe_customer_ids_handler(
|
||||
http_request: HttpRequest,
|
||||
path: Path<ModeratorGetUserStripeCustomerIdsPathInfo>,
|
||||
server_state: web::Data<Arc<ServerState>>,
|
||||
) -> Result<Json<ModeratorGetUserStripeCustomerIdsResponse>, CommonWebError> {
|
||||
|
||||
let mut mysql_connection = server_state.mysql_pool
|
||||
.acquire()
|
||||
.await?;
|
||||
|
||||
let _moderator_session = require_moderator(
|
||||
&http_request,
|
||||
&server_state,
|
||||
UseDatabase::FromPool(&mut mysql_connection),
|
||||
)
|
||||
.await
|
||||
.map_err(|_| CommonWebError::NotAuthorized)?;
|
||||
|
||||
let customer_links = list_user_stripe_customer_links_for_user(&path.user_token, &mut mysql_connection)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
warn!("moderator_get_user_stripe_customer_ids customer link query error: {:?}", err);
|
||||
CommonWebError::from_error(err)
|
||||
})?;
|
||||
|
||||
let subscription_customer_ids = list_stripe_customer_ids_for_user_subscriptions(&path.user_token, &mut mysql_connection)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
warn!("moderator_get_user_stripe_customer_ids subscription query error: {:?}", err);
|
||||
CommonWebError::from_error(err)
|
||||
})?;
|
||||
|
||||
let mut customer_ids = Vec::with_capacity(customer_links.len() + subscription_customer_ids.len());
|
||||
|
||||
customer_ids.extend(customer_links.into_iter().map(|link| ModeratorUserStripeCustomerIdEntry {
|
||||
stripe_dashboard_url: stripe_dashboard_customer_url(&server_state, link.payments_namespace, &link.stripe_customer_id),
|
||||
stripe_customer_id: link.stripe_customer_id,
|
||||
payments_namespace: link.payments_namespace,
|
||||
source: ModeratorStripeCustomerIdSource::CustomerLink,
|
||||
}));
|
||||
|
||||
customer_ids.extend(subscription_customer_ids.into_iter().map(|subscription| ModeratorUserStripeCustomerIdEntry {
|
||||
stripe_dashboard_url: stripe_dashboard_customer_url(&server_state, subscription.subscription_namespace, &subscription.stripe_customer_id),
|
||||
stripe_customer_id: subscription.stripe_customer_id,
|
||||
payments_namespace: subscription.subscription_namespace,
|
||||
source: ModeratorStripeCustomerIdSource::Subscription,
|
||||
}));
|
||||
|
||||
Ok(Json(ModeratorGetUserStripeCustomerIdsResponse {
|
||||
success: true,
|
||||
customer_ids,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Each payments namespace bills through a different Stripe account.
|
||||
fn stripe_dashboard_customer_url(
|
||||
server_state: &ServerState,
|
||||
payments_namespace: PaymentsNamespace,
|
||||
stripe_customer_id: &str,
|
||||
) -> String {
|
||||
let stripe_account_id = match payments_namespace {
|
||||
PaymentsNamespace::Artcraft => &server_state.stripe_artcraft.stripe_account_id,
|
||||
PaymentsNamespace::FakeYou => &server_state.stripe.stripe_account_id,
|
||||
};
|
||||
format!("https://dashboard.stripe.com/{}/customers/{}", stripe_account_id, stripe_customer_id)
|
||||
}
|
||||
-7
@@ -46,7 +46,6 @@ use crate::http_server::endpoints::moderation::user_referrals::moderator_list_gl
|
||||
use crate::http_server::endpoints::moderation::user_referrals::moderator_list_user_referrals_for_user_handler::moderator_list_user_referrals_for_user_handler;
|
||||
use crate::http_server::endpoints::moderation::user_sessions::moderator_list_user_session_impersonation_requests_handler::moderator_list_user_session_impersonation_requests_handler;
|
||||
use crate::http_server::endpoints::moderation::user_sessions::moderator_user_session_impersonation_request_handler::moderator_user_session_impersonation_request_handler;
|
||||
use crate::http_server::endpoints::moderation::user_stripe_data::moderator_get_user_stripe_customer_ids_handler::moderator_get_user_stripe_customer_ids_handler;
|
||||
|
||||
pub fn add_moderator_routes<T, B> (app: App<T>) -> App<T>
|
||||
where
|
||||
@@ -172,12 +171,6 @@ pub fn add_moderator_routes<T, B> (app: App<T>) -> App<T>
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
)
|
||||
.service(web::scope("/user_stripe_data")
|
||||
.service(web::resource("/{user_token}/customer_ids")
|
||||
.route(web::get().to(moderator_get_user_stripe_customer_ids_handler))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
)
|
||||
)
|
||||
.service(web::resource("/wallet_ledger_entry/{wallet_ledger_entry_token}")
|
||||
.route(web::get().to(moderator_get_wallet_ledger_entry_handler))
|
||||
.route(web::head().to(|| HttpResponse::Ok()))
|
||||
|
||||
@@ -5,7 +5,6 @@ use errors::AnyhowResult;
|
||||
|
||||
pub fn setup_stripe_artcraft() -> AnyhowResult<ArtcraftStripeConfigWithClient> {
|
||||
Ok(ArtcraftStripeConfig {
|
||||
stripe_account_id: easyenv::get_env_string_required("STRIPE_ARTCRAFT_ACCOUNT_ID")?,
|
||||
secret_key: easyenv::get_env_string_required("STRIPE_ARTCRAFT_SECRET_KEY")?,
|
||||
secret_webhook_signing_key: easyenv::get_env_string_required("STRIPE_ARTCRAFT_SECRET_WEBHOOK_KEY")?,
|
||||
checkout_success_url: easyenv::get_env_string_required("STRIPE_ARTCRAFT_CHECKOUT_SUCCESS_URL")?,
|
||||
|
||||
@@ -31,6 +31,5 @@ pub fn setup_stripe_fakeyou() -> AnyhowResult<StripeSettings> {
|
||||
Ok(StripeSettings {
|
||||
config: stripe_configs,
|
||||
client: stripe_client,
|
||||
stripe_account_id: easyenv::get_env_string_required("STRIPE_FAKEYOU_ACCOUNT_ID")?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -219,9 +219,6 @@ pub struct EphemeralInMemoryCaches {
|
||||
pub struct StripeSettings {
|
||||
pub config: StripeConfig,
|
||||
pub client: stripe::Client,
|
||||
|
||||
/// The Stripe account id (eg. "acct_..."), used to build dashboard links.
|
||||
pub stripe_account_id: String,
|
||||
}
|
||||
|
||||
/// Flags set at service startup
|
||||
|
||||
+32
-83
@@ -2,21 +2,7 @@
|
||||
|
||||
This is an `nx` monorepo that can contain multiple apps and shared libraries.
|
||||
|
||||
All commands to run these projects are performed from _this_ directory
|
||||
(except the repo-root launcher scripts noted below).
|
||||
|
||||
## Requirements
|
||||
|
||||
- **Node.js 20+** (Nx 21 / Vite 6 requirement). Install via [nvm](https://github.com/nvm-sh/nvm),
|
||||
[nodejs.org](https://nodejs.org), or `brew install node`.
|
||||
- **npm** (ships with Node).
|
||||
|
||||
> **We use npm, not pnpm.** pnpm was briefly adopted ("add pnpm to solve build
|
||||
> issues") and later removed ("fix(frontend): consume video-editor libs via nx
|
||||
> path aliases, drop pnpm"). If you have leftovers from that era — a
|
||||
> `pnpm-lock.yaml`, `pnpm-workspace.yaml`, or a `node_modules/.pnpm` directory —
|
||||
> npm installs will fail (typically with `ENOTEMPTY` rename errors). See
|
||||
> Troubleshooting below.
|
||||
All commands to run these projects are performed from _this_ directory.
|
||||
|
||||
## Install dependencies
|
||||
|
||||
@@ -24,95 +10,58 @@ All commands to run these projects are performed from _this_ directory
|
||||
npm install
|
||||
```
|
||||
|
||||
## Running the apps in dev mode
|
||||
## Editor2d
|
||||
|
||||
From the **repository root**, the launcher scripts (these preflight your
|
||||
environment, install dependencies, and free the dev port first):
|
||||
Run dev server:
|
||||
|
||||
```bash
|
||||
./script/website/unix_frontend_dev.sh # artcraft-website (marketing site), port 4200
|
||||
./script/website/unix_frontend_webapp_dev.sh # artcraft-webapp (user dashboard), port 4201
|
||||
./script/artcraft/unix_frontend_dev.sh # artcraft (Tauri app frontend), port 5173
|
||||
```
|
||||
|
||||
Or directly from this directory:
|
||||
|
||||
```bash
|
||||
nx dev artcraft-website
|
||||
nx dev artcraft-webapp
|
||||
nx dev artcraft # NB: the Tauri app also needs the Rust dev server running
|
||||
nx dev editor2d
|
||||
```
|
||||
|
||||
## Building
|
||||
## artcraft
|
||||
|
||||
Run dev server:
|
||||
|
||||
```bash
|
||||
npx nx build artcraft-website
|
||||
npx nx build artcraft-webapp
|
||||
npx nx build artcraft
|
||||
npx nx build editor2d
|
||||
nx dev artcraft
|
||||
```
|
||||
|
||||
Netlify deploys run `apps/<app>/script/netlify_build.sh` (see each app's
|
||||
`netlify.toml`).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### `npm install` fails with `ENOTEMPTY: directory not empty, rename ...`
|
||||
|
||||
Your `node_modules` tree is corrupted — usually an interrupted install, or a
|
||||
tree written by pnpm back when the repo briefly used it. Fix:
|
||||
|
||||
```bash
|
||||
./clean_modules.sh
|
||||
npm install
|
||||
```
|
||||
call when starting on main or a new branch:
|
||||
./clean_modules
|
||||
|
||||
Or the manual minimum:
|
||||
|
||||
```bash
|
||||
rm -rf node_modules .nx pnpm-lock.yaml pnpm-workspace.yaml
|
||||
npm install
|
||||
```
|
||||
|
||||
### Stale build state after switching branches
|
||||
|
||||
Call this when starting on main or a new branch:
|
||||
|
||||
```bash
|
||||
./clean_modules.sh
|
||||
```
|
||||
|
||||
It removes all `dist/` outputs, resets the nx cache, and removes
|
||||
`node_modules`.
|
||||
|
||||
## Import aliases
|
||||
|
||||
The names for `@frontend` and `@storyteller` come from the `package.json` file
|
||||
in the libs folder:
|
||||
|
||||
```ts
|
||||
The names for @frontend and @storyteller come from the package.json file in the libs folder.
|
||||
import { Login } from "@frontend/login";
|
||||
import { api } from "@storyteller/api";
|
||||
```
|
||||
|
||||
For shared UI components, import from `@storyteller/ui-[componentname]`:
|
||||
|
||||
```ts
|
||||
For shared UI components, import from @storyteller/ui-[componentname].
|
||||
import { Button } from "@storyteller/ui-button";
|
||||
import { Modal } from "@storyteller/ui-modal";
|
||||
```
|
||||
|
||||
## Generating a new component library
|
||||
building:
|
||||
npx nx build artcraft
|
||||
npx nx build editor2d
|
||||
|
||||
```bash
|
||||
# 1. Generate the library
|
||||
dev:
|
||||
npx nx dev artcraft
|
||||
npx nx dev editor2d
|
||||
|
||||
|
||||
|
||||
# component build
|
||||
1.
|
||||
npx nx g @nx/react:library libs/components/toaster --import-path=@storyteller/ui-toaster --bundler=vite
|
||||
npm install
|
||||
2.import it first in code
|
||||
3.nx sync
|
||||
4.nx build
|
||||
|
||||
# 2. Import it somewhere in code
|
||||
or
|
||||
|
||||
# 3. Sync and build
|
||||
nx sync
|
||||
nx build
|
||||
# frontend build
|
||||
in frontend folder
|
||||
|
||||
% nx build -project type
|
||||
% nx build artcraft
|
||||
% nx dev artcraft
|
||||
```
|
||||
|
||||
Generated
+36
-3
@@ -3066,7 +3066,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.0.tgz",
|
||||
"integrity": "sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@emnapi/wasi-threads": "1.2.2",
|
||||
"tslib": "^2.4.0"
|
||||
@@ -3077,7 +3076,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.0.tgz",
|
||||
"integrity": "sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
@@ -13372,6 +13370,42 @@
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/core": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
||||
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@emnapi/wasi-threads": "1.2.1",
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/runtime": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
|
||||
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
|
||||
"integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
|
||||
@@ -27256,7 +27290,6 @@
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
root_dir=$(pwd)
|
||||
frontend_path="${root_dir}/frontend"
|
||||
|
||||
source "${root_dir}/script/common/frontend_preflight.sh"
|
||||
frontend_preflight "${frontend_path}"
|
||||
|
||||
echo "Running Artcraft Frontend in Dev Mode..."
|
||||
echo ""
|
||||
|
||||
@@ -23,7 +20,7 @@ fi
|
||||
|
||||
pushd "${frontend_path}" || exit
|
||||
|
||||
frontend_npm_install
|
||||
npm install --verbose
|
||||
|
||||
export VITE_ENVIRONMENT_TYPE="production"
|
||||
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Shared preflight checks for the frontend dev/build scripts.
|
||||
#
|
||||
# Usage (from a script that has set ${frontend_path}):
|
||||
#
|
||||
# source "${root_dir}/script/common/frontend_preflight.sh"
|
||||
# frontend_preflight "${frontend_path}"
|
||||
# ...
|
||||
# pushd "${frontend_path}"
|
||||
# frontend_npm_install
|
||||
#
|
||||
|
||||
# Node 20+ is required by Nx 21 and comfortably covers Vite 6.
|
||||
FRONTEND_MINIMUM_NODE_MAJOR=20
|
||||
|
||||
frontend_preflight() {
|
||||
local frontend_path="$1"
|
||||
|
||||
if [ ! -d "${frontend_path}" ]; then
|
||||
echo "ERROR: frontend directory not found at: ${frontend_path}"
|
||||
echo "Run this script from the repository root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Node and npm must be installed ---
|
||||
if ! command -v node &>/dev/null; then
|
||||
echo "ERROR: node is not installed (or not on PATH)."
|
||||
echo "Install Node.js ${FRONTEND_MINIMUM_NODE_MAJOR}+ via nvm (https://github.com/nvm-sh/nvm),"
|
||||
echo "https://nodejs.org, or:"
|
||||
echo " brew install node"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v npm &>/dev/null; then
|
||||
echo "ERROR: npm is not installed (or not on PATH). It normally ships with Node.js."
|
||||
echo "Reinstall Node.js to get it back."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Node must be recent enough for Nx 21 / Vite 6 ---
|
||||
local node_major
|
||||
node_major=$(node --version | sed -E 's/^v([0-9]+).*/\1/')
|
||||
if [ "${node_major}" -lt "${FRONTEND_MINIMUM_NODE_MAJOR}" ]; then
|
||||
echo "ERROR: Node.js ${FRONTEND_MINIMUM_NODE_MAJOR}+ is required (found $(node --version))."
|
||||
echo "Upgrade via nvm ('nvm install --lts') or https://nodejs.org."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- The frontend uses npm; stale pnpm state breaks installs ---
|
||||
# pnpm was briefly adopted ("add pnpm to solve build issues") and then dropped
|
||||
# ("fix(frontend): consume video-editor libs via nx path aliases, drop pnpm").
|
||||
# A node_modules tree written by pnpm makes npm fail with ENOTEMPTY errors.
|
||||
if [ -e "${frontend_path}/pnpm-lock.yaml" ] \
|
||||
|| [ -e "${frontend_path}/pnpm-workspace.yaml" ] \
|
||||
|| [ -d "${frontend_path}/node_modules/.pnpm" ]; then
|
||||
echo "ERROR: Stale pnpm artifacts detected in ${frontend_path}."
|
||||
echo "The frontend uses npm (pnpm was dropped; see frontend/README.md)."
|
||||
echo "Clean up with:"
|
||||
echo " cd ${frontend_path} && rm -rf node_modules pnpm-lock.yaml pnpm-workspace.yaml && npm install"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Run `npm install` in the current directory. If it fails (typically from a
|
||||
# corrupted node_modules tree, eg. an interrupted install or a leftover pnpm
|
||||
# layout causing ENOTEMPTY rename errors), wipe node_modules and the nx cache
|
||||
# and retry once before giving up.
|
||||
frontend_npm_install() {
|
||||
if npm install; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "WARNING: npm install failed. node_modules may be corrupted (eg. an"
|
||||
echo "interrupted install or a mixed npm/pnpm tree). Wiping and retrying..."
|
||||
echo ""
|
||||
|
||||
rm -rf node_modules .nx
|
||||
|
||||
if ! npm install; then
|
||||
echo ""
|
||||
echo "ERROR: npm install failed again. See the npm output above and the"
|
||||
echo "troubleshooting section in frontend/README.md."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
@@ -4,9 +4,6 @@
|
||||
root_dir=$(pwd)
|
||||
frontend_path="${root_dir}/frontend"
|
||||
|
||||
source "${root_dir}/script/common/frontend_preflight.sh"
|
||||
frontend_preflight "${frontend_path}"
|
||||
|
||||
echo "Running Artcraft Website in Dev Mode..."
|
||||
echo ""
|
||||
|
||||
@@ -20,7 +17,7 @@ fi
|
||||
|
||||
pushd "${frontend_path}" || exit
|
||||
|
||||
frontend_npm_install
|
||||
npm install --verbose
|
||||
|
||||
export VITE_ENVIRONMENT_TYPE="production"
|
||||
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
root_dir=$(pwd)
|
||||
frontend_path="${root_dir}/frontend"
|
||||
|
||||
source "${root_dir}/script/common/frontend_preflight.sh"
|
||||
frontend_preflight "${frontend_path}"
|
||||
|
||||
echo "Running Artcraft Webapp in Dev Mode..."
|
||||
echo ""
|
||||
|
||||
@@ -20,7 +17,7 @@ fi
|
||||
|
||||
pushd "${frontend_path}" || exit
|
||||
|
||||
frontend_npm_install
|
||||
npm install --verbose
|
||||
|
||||
export VITE_ENVIRONMENT_TYPE="production"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user