Update sharing settings
This commit is contained in:
@@ -11,6 +11,7 @@ export type GenericResponse = {
|
||||
}
|
||||
|
||||
export type User = {
|
||||
id: string,
|
||||
username: string,
|
||||
email: string,
|
||||
otp_enabled: boolean,
|
||||
@@ -20,12 +21,10 @@ export type User = {
|
||||
filesystem_node_count: number,
|
||||
is_admin: boolean,
|
||||
balance_micro_eur: number,
|
||||
hotlinking_enabled: boolean,
|
||||
monthly_transfer_cap: number,
|
||||
monthly_transfer_used: number,
|
||||
file_viewer_branding: Map<string, string>,
|
||||
file_embed_domains: string,
|
||||
skip_file_viewer: boolean,
|
||||
embed_domains: string,
|
||||
affiliate_user_name: string,
|
||||
checkout_country: string,
|
||||
checkout_name: string,
|
||||
@@ -158,10 +157,12 @@ export const put_user = async (data: Object) => {
|
||||
))
|
||||
|
||||
// Update the user store
|
||||
for (let key of Object.keys(data)) {
|
||||
cached_user[key] = data[key]
|
||||
}
|
||||
user.set(cached_user)
|
||||
user.update((user: User) => {
|
||||
for (let key of Object.keys(data)) {
|
||||
user[key] = data[key]
|
||||
}
|
||||
return user
|
||||
})
|
||||
}
|
||||
|
||||
export const logout_user = async (redirect_path: string) => {
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
<script>
|
||||
import { preventDefault } from 'svelte/legacy';
|
||||
import { onMount } from "svelte";
|
||||
import Pro from "icons/Pro.svelte";
|
||||
import { formatDataVolume } from "util/Formatting";
|
||||
import ProgressBar from "util/ProgressBar.svelte";
|
||||
import SuccessMessage from "util/SuccessMessage.svelte";
|
||||
import { loading_finish, loading_start } from "lib/Loading";
|
||||
import { put_user } from 'lib/NovaAPI';
|
||||
import { user } from 'lib/UserStore';
|
||||
|
||||
let success_message = $state()
|
||||
let hotlinking = $state($user === null ? false : $user.hotlinking_enabled)
|
||||
let transfer_cap = $state($user === null ? 0 : $user.monthly_transfer_cap / 1e12)
|
||||
let skip_viewer = $state($user === null ? false : $user.skip_file_viewer)
|
||||
|
||||
const update = async () => {
|
||||
loading_start()
|
||||
try {
|
||||
await put_user({
|
||||
hotlinking_enabled: hotlinking,
|
||||
transfer_cap: transfer_cap*1e12,
|
||||
skip_file_viewer: skip_viewer,
|
||||
})
|
||||
|
||||
success_message.set(true, "Sharing settings updated")
|
||||
} catch (err) {
|
||||
success_message.set(false, "Failed to update subscription: "+err)
|
||||
} finally {
|
||||
loading_finish()
|
||||
}
|
||||
}
|
||||
|
||||
let toggle_hotlinking = () => {
|
||||
hotlinking = !hotlinking
|
||||
update()
|
||||
}
|
||||
|
||||
let transfer_used = $state(0)
|
||||
let load_transfer_used = () => {
|
||||
let today = new Date()
|
||||
let start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
|
||||
fetch(
|
||||
window.api_endpoint + "/user/time_series/egress" +
|
||||
"?start=" + start.toISOString() +
|
||||
"&end=" + today.toISOString() +
|
||||
"&interval=60"
|
||||
).then(resp => {
|
||||
if (!resp.ok) { return Promise.reject("Error: " + resp.status); }
|
||||
return resp.json();
|
||||
}).then(resp => {
|
||||
transfer_used = resp.amounts.reduce((acc, cur) => { return acc + cur }, 0)
|
||||
}).catch(e => {
|
||||
console.error("Error requesting time series: " + e);
|
||||
})
|
||||
}
|
||||
|
||||
let toggle_skip_viewer = () => {
|
||||
skip_viewer = !skip_viewer
|
||||
update()
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
load_transfer_used()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<section>
|
||||
<h2><Pro/>Hotlinking (bandwidth sharing)</h2>
|
||||
<SuccessMessage bind:this={success_message}></SuccessMessage>
|
||||
|
||||
<button onclick={toggle_hotlinking}>
|
||||
{#if hotlinking}
|
||||
<i class="icon green">check</i> ON (click to turn off)
|
||||
{:else}
|
||||
<i class="icon red">close</i> OFF (click to turn on)
|
||||
{/if}
|
||||
</button>
|
||||
<p>
|
||||
When hotlinking is enabled all the bandwidth that your files use will be
|
||||
subtracted from your data cap. Advertisements will be disabled on the
|
||||
download pages for your files and download speed will be unlimited. The
|
||||
rate limiting captcha for files is also disabled when hotlinking is on.
|
||||
You can directly embed your file's download link anywhere, you don't
|
||||
need to use the file viewer page.
|
||||
</p>
|
||||
|
||||
<h2><Pro/>Bill shock limit</h2>
|
||||
<p>
|
||||
Billshock limit in terabytes per month (1 TB = 1000 GB). Set to 0 to
|
||||
disable.
|
||||
</p>
|
||||
<form onsubmit={preventDefault(update)} class="billshock_container">
|
||||
<input type="number" bind:value={transfer_cap} step="0.1" min="0" style="width: 5em;"/>
|
||||
<div style="margin: 0.5em;">TB</div>
|
||||
<button type="submit">
|
||||
<i class="icon">save</i> Save
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<p>
|
||||
Bandwidth used in the last 30 days: {formatDataVolume(transfer_used, 3)},
|
||||
new limit: {formatDataVolume(transfer_cap*1e12, 3)}
|
||||
</p>
|
||||
<ProgressBar used={transfer_used} total={transfer_cap*1e12}></ProgressBar>
|
||||
<p>
|
||||
The billshock limit limits how much bandwidth your account can use in a
|
||||
30 day window. When this limit is reached hotlinking will be disabled
|
||||
and you will no longer be charged for bandwidth usage. This is mostly
|
||||
useful for the Prepaid subscription, but it works for Patreon plans too.
|
||||
Set to 0 to disable the limit.
|
||||
</p>
|
||||
|
||||
<h2><Pro/>Skip download page</h2>
|
||||
<button onclick={toggle_skip_viewer}>
|
||||
{#if skip_viewer}
|
||||
<i class="icon green">check</i> ON (click to turn off)
|
||||
{:else}
|
||||
<i class="icon red">close</i> OFF (click to turn on)
|
||||
{/if}
|
||||
</button>
|
||||
<p>
|
||||
This setting only applies to your account, others will still see the
|
||||
download page when visiting your files. When this is enabled you will be
|
||||
redirected to the file download API when clicking a Nova link.
|
||||
This means that images, videos and PDF files will be opened directly in
|
||||
your browser, and other files are immediately downloaded to your device.
|
||||
This only works for single file links, not albums. You will need a Pro
|
||||
subscription to use this feature.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.green {
|
||||
color: var(--highlight_color);
|
||||
}
|
||||
.red {
|
||||
color: var(--danger_color);
|
||||
}
|
||||
.billshock_container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,118 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import SuccessMessage from "util/SuccessMessage.svelte";
|
||||
import { get_endpoint, get_user, type User } from "lib/NovaAPI";
|
||||
import { loading_run } from "lib/Loading";
|
||||
|
||||
let success_message: SuccessMessage
|
||||
|
||||
// Embedding settings
|
||||
let embed_domains: string[] = []
|
||||
|
||||
const save_embed = async () => {
|
||||
await loading_run(async () => {
|
||||
const domain_list = embed_domains.join(" ")
|
||||
const form = new FormData()
|
||||
form.append("embed_domains", domain_list)
|
||||
|
||||
try {
|
||||
const resp = await fetch(
|
||||
get_endpoint()+"/user",
|
||||
{ method: "PUT", body: form }
|
||||
);
|
||||
if(resp.status >= 400) {
|
||||
let json = await resp.json()
|
||||
console.debug(json)
|
||||
throw json.message
|
||||
}
|
||||
|
||||
success_message.set(true, "Changes saved")
|
||||
} catch(err) {
|
||||
success_message.set(false, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let new_domain: string = ""
|
||||
const add = () => {
|
||||
console.debug("Adding domain", new_domain)
|
||||
embed_domains.push(new_domain)
|
||||
embed_domains = embed_domains
|
||||
new_domain = ""
|
||||
save_embed()
|
||||
}
|
||||
const remove = (index: number) => {
|
||||
embed_domains.splice(index, 1)
|
||||
embed_domains = embed_domains
|
||||
save_embed()
|
||||
}
|
||||
|
||||
let user: User
|
||||
onMount(async () => {
|
||||
user = await get_user()
|
||||
if (user.file_embed_domains !== "") {
|
||||
embed_domains = user.file_embed_domains.split(" ")
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<section>
|
||||
<h2>Embedding controls</h2>
|
||||
<SuccessMessage bind:this={success_message}></SuccessMessage>
|
||||
{#if user !== undefined && !user.hotlinking_enabled}
|
||||
<div class="highlight_yellow">
|
||||
To use embedding restrictions hotlinking needs to be enabled.
|
||||
Enable hotlinking on the
|
||||
<a href="/user/sharing/bandwidth">sharing settings page</a>.
|
||||
</div>
|
||||
{/if}
|
||||
<p>
|
||||
Here you can control which websites are allowed to embed your files in
|
||||
their web pages. If a website that is not on this list tries to embed
|
||||
one of your files the request will be blocked. This applies to both
|
||||
hotlink and iframe embeds. If the list is empty, all domains are allowed
|
||||
to embed your files.
|
||||
</p>
|
||||
<div class="highlight_border">
|
||||
<form on:submit|preventDefault={() => add()}>
|
||||
<div class="form_row">
|
||||
<span>Add domain name</span>
|
||||
<input class="grow" bind:value={new_domain} type="text"/>
|
||||
<button class="shrink" type="submit"><i class="icon">add</i> Add</button>
|
||||
</div>
|
||||
</form>
|
||||
<hr/>
|
||||
{#if embed_domains.length === 0}
|
||||
<span>
|
||||
No domains specified. All websites are allowed to embed your files
|
||||
</span>
|
||||
{/if}
|
||||
{#each embed_domains as domain, index}
|
||||
<div class="form_row">
|
||||
<button class="shrink" type="button" on:click={() => remove(index)}>
|
||||
<i class="icon">delete</i>
|
||||
</button>
|
||||
<div>{domain}</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.highlight_border {
|
||||
text-align: initial;
|
||||
}
|
||||
.form_row {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
}
|
||||
.grow {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.shrink {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
</style>
|
||||
@@ -7,12 +7,11 @@ import ConnectApp from "./ConnectApp.svelte";
|
||||
import ActivityLog from "./ActivityLog.svelte";
|
||||
import DepositCredit from "./DepositCredit.svelte";
|
||||
import TabMenu, { type Tab } from "util/TabMenu.svelte";
|
||||
import BandwidthSharing from "./BandwidthSharing.svelte";
|
||||
import EmbeddingControls from "./EmbeddingControls.svelte";
|
||||
import Dashboard from "./dashboard/Dashboard.svelte";
|
||||
import AffiliatePrompt from "./AffiliatePrompt.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import { get_user, type User } from "lib/NovaAPI";
|
||||
import SharingSettings from "./SharingSettings.svelte";
|
||||
|
||||
let pages: Tab[] = [
|
||||
{
|
||||
@@ -50,21 +49,9 @@ let pages: Tab[] = [
|
||||
],
|
||||
}, {
|
||||
path: "/user/sharing",
|
||||
title: "Sharing",
|
||||
title: "Sharing settings",
|
||||
icon: "share",
|
||||
subpages: [
|
||||
{
|
||||
path: "/user/sharing/bandwidth",
|
||||
title: "Sharing settings",
|
||||
icon: "share",
|
||||
component: BandwidthSharing,
|
||||
}, {
|
||||
path: "/user/sharing/embedding",
|
||||
title: "Embedding Controls",
|
||||
icon: "code",
|
||||
component: EmbeddingControls,
|
||||
},
|
||||
],
|
||||
component: SharingSettings,
|
||||
}, {
|
||||
path: "/user/connect_app",
|
||||
title: "Apps",
|
||||
|
||||
160
svelte/src/user_home/SharingSettings.svelte
Normal file
160
svelte/src/user_home/SharingSettings.svelte
Normal file
@@ -0,0 +1,160 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { formatDataVolume } from "util/Formatting";
|
||||
import ProgressBar from "util/ProgressBar.svelte";
|
||||
import { loading_run } from "lib/Loading";
|
||||
import { get_endpoint, put_user } from 'lib/NovaAPI';
|
||||
import SuccessMessage from 'util/SuccessMessage.svelte';
|
||||
import { user } from "lib/UserStore";
|
||||
|
||||
let success_message: SuccessMessage = $state()
|
||||
let transfer_cap = $state($user === null ? 0 : $user.monthly_transfer_cap / 1e12)
|
||||
|
||||
const update_user = async (e: SubmitEvent) => {
|
||||
if (e !== null) {
|
||||
e.preventDefault()
|
||||
}
|
||||
loading_run(async () => {
|
||||
try {
|
||||
await put_user({
|
||||
transfer_cap: transfer_cap*1e12,
|
||||
embed_domains: embed_domains.join(" "),
|
||||
})
|
||||
|
||||
success_message.set(true, "Sharing settings updated")
|
||||
} catch (err) {
|
||||
success_message.set(false, "Failed to update user: "+err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let transfer_used = $state(0)
|
||||
let load_transfer_used = () => {
|
||||
let today = new Date()
|
||||
let start = new Date()
|
||||
start.setDate(start.getDate() - 30)
|
||||
|
||||
fetch(
|
||||
get_endpoint() + "/user/time_series/egress" +
|
||||
"?start=" + start.toISOString() +
|
||||
"&end=" + today.toISOString() +
|
||||
"&interval=60"
|
||||
).then(resp => {
|
||||
if (!resp.ok) { return Promise.reject("Error: " + resp.status); }
|
||||
return resp.json();
|
||||
}).then(resp => {
|
||||
transfer_used = resp.amounts.reduce((acc, cur) => { return acc + cur }, 0)
|
||||
}).catch(e => {
|
||||
console.error("Error requesting time series: " + e);
|
||||
})
|
||||
}
|
||||
|
||||
// Embedding settings
|
||||
let embed_domains: string[] = $state($user === null ? [] : $user.embed_domains.split(" "))
|
||||
let new_domain: string = $state("")
|
||||
|
||||
const add_domain = (e: SubmitEvent) => {
|
||||
e.preventDefault()
|
||||
console.debug("Adding domain", new_domain)
|
||||
embed_domains.push(new_domain)
|
||||
embed_domains = embed_domains
|
||||
new_domain = ""
|
||||
update_user(e)
|
||||
}
|
||||
const del_domain = (index: number) => {
|
||||
embed_domains.splice(index, 1)
|
||||
embed_domains = embed_domains
|
||||
update_user(null)
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
load_transfer_used()
|
||||
})
|
||||
</script>
|
||||
|
||||
<section>
|
||||
<SuccessMessage bind:this={success_message}/>
|
||||
|
||||
<h2>Bill shock limit</h2>
|
||||
<p>
|
||||
Billshock limit in terabytes per month (1 TB = 1000 GB). Set to 0 to
|
||||
disable.
|
||||
</p>
|
||||
<form onsubmit={update_user} class="billshock_container">
|
||||
<input type="number" bind:value={transfer_cap} step="0.1" min="0" style="width: 5em;"/>
|
||||
<div style="margin: 0.5em;">TB</div>
|
||||
<button type="submit">
|
||||
<i class="icon">save</i> Save
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<p>
|
||||
Bandwidth used in the last 30 days: {formatDataVolume(transfer_used, 3)},
|
||||
new limit: {formatDataVolume(transfer_cap*1e12, 3)}
|
||||
</p>
|
||||
<ProgressBar used={transfer_used} total={transfer_cap*1e12}></ProgressBar>
|
||||
<p>
|
||||
The billshock limit limits how much bandwidth your account can use in a
|
||||
30 day window. When this limit is reached hotlinking will be disabled
|
||||
and you will no longer be charged for bandwidth usage. This is mostly
|
||||
useful for the Prepaid subscription, but it works for Patreon plans too.
|
||||
Set to 0 to disable the limit.
|
||||
</p>
|
||||
|
||||
<h2>Embedding controls</h2>
|
||||
<p>
|
||||
Here you can control which websites are allowed to embed your files in
|
||||
their web pages. If a website that is not on this list tries to embed
|
||||
one of your files the request will be blocked. This applies to both
|
||||
hotlink and iframe embeds. If the list is empty, all domains are allowed
|
||||
to embed your files.
|
||||
</p>
|
||||
<div class="highlight_border">
|
||||
<form onsubmit={add_domain}>
|
||||
<div class="form_row">
|
||||
<span>Add domain name</span>
|
||||
<input class="grow" bind:value={new_domain} type="text"/>
|
||||
<button class="shrink" type="submit"><i class="icon">add</i> Add</button>
|
||||
</div>
|
||||
</form>
|
||||
<hr/>
|
||||
{#if embed_domains.length === 0}
|
||||
<span>
|
||||
No domains specified. All websites are allowed to embed your files
|
||||
</span>
|
||||
{/if}
|
||||
{#each embed_domains as domain, index}
|
||||
<div class="form_row">
|
||||
<button class="shrink" type="button" onclick={() => del_domain(index)}>
|
||||
<i class="icon">delete</i>
|
||||
</button>
|
||||
<div>{domain}</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.billshock_container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.highlight_border {
|
||||
text-align: initial;
|
||||
}
|
||||
.form_row {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
}
|
||||
.grow {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.shrink {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user