mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2026-01-03 12:03:17 -06:00
Merge branch 'main' into instance-custom-css
This commit is contained in:
commit
7cd9b0eae0
947 changed files with 689490 additions and 178161 deletions
|
|
@ -110,12 +110,19 @@ export function MenuItem(props: PropsWithChildren<MenuItemProps>) {
|
|||
if (topLevel) {
|
||||
classNames.push("category", "top-level");
|
||||
} else {
|
||||
if (thisLevel === 1 && hasChildren) {
|
||||
classNames.push("category", "expanding");
|
||||
} else if (thisLevel === 1 && !hasChildren) {
|
||||
classNames.push("view", "expanding");
|
||||
} else if (thisLevel === 2) {
|
||||
classNames.push("view", "nested");
|
||||
switch (true) {
|
||||
case thisLevel === 1 && hasChildren:
|
||||
classNames.push("category", "expanding");
|
||||
break;
|
||||
case thisLevel === 1 && !hasChildren:
|
||||
classNames.push("view", "expanding");
|
||||
break;
|
||||
case thisLevel >= 2 && hasChildren:
|
||||
classNames.push("nested", "category");
|
||||
break;
|
||||
case thisLevel >= 2 && !hasChildren:
|
||||
classNames.push("nested", "view");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
173
web/source/settings/lib/query/admin/domain-permissions/drafts.ts
Normal file
173
web/source/settings/lib/query/admin/domain-permissions/drafts.ts
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { gtsApi } from "../../gts-api";
|
||||
|
||||
import type {
|
||||
DomainPerm,
|
||||
DomainPermDraftCreateParams,
|
||||
DomainPermDraftSearchParams,
|
||||
DomainPermDraftSearchResp,
|
||||
} from "../../../types/domain-permission";
|
||||
import parse from "parse-link-header";
|
||||
import { PermType } from "../../../types/perm";
|
||||
|
||||
const extended = gtsApi.injectEndpoints({
|
||||
endpoints: (build) => ({
|
||||
searchDomainPermissionDrafts: build.query<DomainPermDraftSearchResp, DomainPermDraftSearchParams>({
|
||||
query: (form) => {
|
||||
const params = new(URLSearchParams);
|
||||
Object.entries(form).forEach(([k, v]) => {
|
||||
if (v !== undefined) {
|
||||
params.append(k, v);
|
||||
}
|
||||
});
|
||||
|
||||
let query = "";
|
||||
if (params.size !== 0) {
|
||||
query = `?${params.toString()}`;
|
||||
}
|
||||
|
||||
return {
|
||||
url: `/api/v1/admin/domain_permission_drafts${query}`
|
||||
};
|
||||
},
|
||||
// Headers required for paging.
|
||||
transformResponse: (apiResp: DomainPerm[], meta) => {
|
||||
const drafts = apiResp;
|
||||
const linksStr = meta?.response?.headers.get("Link");
|
||||
const links = parse(linksStr);
|
||||
return { drafts, links };
|
||||
},
|
||||
// Only provide TRANSFORMED tag id since this model is not the same
|
||||
// as getDomainPermissionDraft model (due to transformResponse).
|
||||
providesTags: [{ type: "DomainPermissionDraft", id: "TRANSFORMED" }]
|
||||
}),
|
||||
|
||||
getDomainPermissionDraft: build.query<DomainPerm, string>({
|
||||
query: (id) => ({
|
||||
url: `/api/v1/admin/domain_permission_drafts/${id}`
|
||||
}),
|
||||
providesTags: (_result, _error, id) => [
|
||||
{ type: 'DomainPermissionDraft', id }
|
||||
],
|
||||
}),
|
||||
|
||||
createDomainPermissionDraft: build.mutation<DomainPerm, DomainPermDraftCreateParams>({
|
||||
query: (formData) => ({
|
||||
method: "POST",
|
||||
url: `/api/v1/admin/domain_permission_drafts`,
|
||||
asForm: true,
|
||||
body: formData,
|
||||
discardEmpty: true
|
||||
}),
|
||||
invalidatesTags: [{ type: "DomainPermissionDraft", id: "TRANSFORMED" }],
|
||||
}),
|
||||
|
||||
acceptDomainPermissionDraft: build.mutation<DomainPerm, { id: string, overwrite?: boolean, permType: PermType }>({
|
||||
query: ({ id, overwrite }) => ({
|
||||
method: "POST",
|
||||
url: `/api/v1/admin/domain_permission_drafts/${id}/accept`,
|
||||
asForm: true,
|
||||
body: {
|
||||
overwrite: overwrite,
|
||||
},
|
||||
discardEmpty: true
|
||||
}),
|
||||
invalidatesTags: (res, _error, { id, permType }) => {
|
||||
const invalidated: any[] = [];
|
||||
|
||||
// If error, nothing to invalidate.
|
||||
if (!res) {
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
// Invalidate this draft by ID, and
|
||||
// the transformed list of all drafts.
|
||||
invalidated.push(
|
||||
{ type: 'DomainPermissionDraft', id: id },
|
||||
{ type: "DomainPermissionDraft", id: "TRANSFORMED" },
|
||||
);
|
||||
|
||||
// Invalidate cached blocks/allows depending
|
||||
// on the permType of the accepted draft.
|
||||
if (permType === "allow") {
|
||||
invalidated.push("domainAllows");
|
||||
} else {
|
||||
invalidated.push("domainBlocks");
|
||||
}
|
||||
|
||||
return invalidated;
|
||||
}
|
||||
}),
|
||||
|
||||
removeDomainPermissionDraft: build.mutation<DomainPerm, { id: string, exclude_target?: boolean }>({
|
||||
query: ({ id, exclude_target }) => ({
|
||||
method: "POST",
|
||||
url: `/api/v1/admin/domain_permission_drafts/${id}/remove`,
|
||||
asForm: true,
|
||||
body: {
|
||||
exclude_target: exclude_target,
|
||||
},
|
||||
discardEmpty: true
|
||||
}),
|
||||
invalidatesTags: (res, _error, { id }) =>
|
||||
res
|
||||
? [
|
||||
{ type: "DomainPermissionDraft", id },
|
||||
{ type: "DomainPermissionDraft", id: "TRANSFORMED" },
|
||||
]
|
||||
: [],
|
||||
})
|
||||
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
* View domain permission drafts.
|
||||
*/
|
||||
const useLazySearchDomainPermissionDraftsQuery = extended.useLazySearchDomainPermissionDraftsQuery;
|
||||
|
||||
/**
|
||||
* Get domain permission draft with the given ID.
|
||||
*/
|
||||
const useGetDomainPermissionDraftQuery = extended.useGetDomainPermissionDraftQuery;
|
||||
|
||||
/**
|
||||
* Create a domain permission draft with the given parameters.
|
||||
*/
|
||||
const useCreateDomainPermissionDraftMutation = extended.useCreateDomainPermissionDraftMutation;
|
||||
|
||||
/**
|
||||
* Accept a domain permission draft, turning it into an enforced domain permission.
|
||||
*/
|
||||
const useAcceptDomainPermissionDraftMutation = extended.useAcceptDomainPermissionDraftMutation;
|
||||
|
||||
/**
|
||||
* Remove a domain permission draft, optionally ignoring all future drafts targeting the given domain.
|
||||
*/
|
||||
const useRemoveDomainPermissionDraftMutation = extended.useRemoveDomainPermissionDraftMutation;
|
||||
|
||||
export {
|
||||
useLazySearchDomainPermissionDraftsQuery,
|
||||
useGetDomainPermissionDraftQuery,
|
||||
useCreateDomainPermissionDraftMutation,
|
||||
useAcceptDomainPermissionDraftMutation,
|
||||
useRemoveDomainPermissionDraftMutation,
|
||||
};
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { gtsApi } from "../../gts-api";
|
||||
|
||||
import type {
|
||||
DomainPerm,
|
||||
DomainPermExcludeCreateParams,
|
||||
DomainPermExcludeSearchParams,
|
||||
DomainPermExcludeSearchResp,
|
||||
} from "../../../types/domain-permission";
|
||||
import parse from "parse-link-header";
|
||||
|
||||
const extended = gtsApi.injectEndpoints({
|
||||
endpoints: (build) => ({
|
||||
searchDomainPermissionExcludes: build.query<DomainPermExcludeSearchResp, DomainPermExcludeSearchParams>({
|
||||
query: (form) => {
|
||||
const params = new(URLSearchParams);
|
||||
Object.entries(form).forEach(([k, v]) => {
|
||||
if (v !== undefined) {
|
||||
params.append(k, v);
|
||||
}
|
||||
});
|
||||
|
||||
let query = "";
|
||||
if (params.size !== 0) {
|
||||
query = `?${params.toString()}`;
|
||||
}
|
||||
|
||||
return {
|
||||
url: `/api/v1/admin/domain_permission_excludes${query}`
|
||||
};
|
||||
},
|
||||
// Headers required for paging.
|
||||
transformResponse: (apiResp: DomainPerm[], meta) => {
|
||||
const excludes = apiResp;
|
||||
const linksStr = meta?.response?.headers.get("Link");
|
||||
const links = parse(linksStr);
|
||||
return { excludes, links };
|
||||
},
|
||||
// Only provide TRANSFORMED tag id since this model is not the same
|
||||
// as getDomainPermissionExclude model (due to transformResponse).
|
||||
providesTags: [{ type: "DomainPermissionExclude", id: "TRANSFORMED" }]
|
||||
}),
|
||||
|
||||
getDomainPermissionExclude: build.query<DomainPerm, string>({
|
||||
query: (id) => ({
|
||||
url: `/api/v1/admin/domain_permission_excludes/${id}`
|
||||
}),
|
||||
providesTags: (_result, _error, id) => [
|
||||
{ type: 'DomainPermissionExclude', id }
|
||||
],
|
||||
}),
|
||||
|
||||
createDomainPermissionExclude: build.mutation<DomainPerm, DomainPermExcludeCreateParams>({
|
||||
query: (formData) => ({
|
||||
method: "POST",
|
||||
url: `/api/v1/admin/domain_permission_excludes`,
|
||||
asForm: true,
|
||||
body: formData,
|
||||
discardEmpty: true
|
||||
}),
|
||||
invalidatesTags: [{ type: "DomainPermissionExclude", id: "TRANSFORMED" }],
|
||||
}),
|
||||
|
||||
deleteDomainPermissionExclude: build.mutation<DomainPerm, string>({
|
||||
query: (id) => ({
|
||||
method: "DELETE",
|
||||
url: `/api/v1/admin/domain_permission_excludes/${id}`,
|
||||
}),
|
||||
invalidatesTags: (res, _error, id) =>
|
||||
res
|
||||
? [
|
||||
{ type: "DomainPermissionExclude", id },
|
||||
{ type: "DomainPermissionExclude", id: "TRANSFORMED" },
|
||||
]
|
||||
: [],
|
||||
})
|
||||
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
* View domain permission excludes.
|
||||
*/
|
||||
const useLazySearchDomainPermissionExcludesQuery = extended.useLazySearchDomainPermissionExcludesQuery;
|
||||
|
||||
/**
|
||||
* Get domain permission exclude with the given ID.
|
||||
*/
|
||||
const useGetDomainPermissionExcludeQuery = extended.useGetDomainPermissionExcludeQuery;
|
||||
|
||||
/**
|
||||
* Create a domain permission exclude with the given parameters.
|
||||
*/
|
||||
const useCreateDomainPermissionExcludeMutation = extended.useCreateDomainPermissionExcludeMutation;
|
||||
|
||||
/**
|
||||
* Delete a domain permission exclude.
|
||||
*/
|
||||
const useDeleteDomainPermissionExcludeMutation = extended.useDeleteDomainPermissionExcludeMutation;
|
||||
|
||||
export {
|
||||
useLazySearchDomainPermissionExcludesQuery,
|
||||
useGetDomainPermissionExcludeQuery,
|
||||
useCreateDomainPermissionExcludeMutation,
|
||||
useDeleteDomainPermissionExcludeMutation,
|
||||
};
|
||||
|
|
@ -37,6 +37,12 @@ const extended = gtsApi.injectEndpoints({
|
|||
}),
|
||||
transformResponse: listToKeyedObject<DomainPerm>("domain"),
|
||||
}),
|
||||
|
||||
domainPermissionDrafts: build.query<any, void>({
|
||||
query: () => ({
|
||||
url: `/api/v1/admin/domain_permission_drafts`
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import {
|
|||
type DomainPerm,
|
||||
type ImportDomainPermsParams,
|
||||
type MappedDomainPerms,
|
||||
isDomainPermInternalKey,
|
||||
stripOnImport,
|
||||
} from "../../../types/domain-permission";
|
||||
import { listToKeyedObject } from "../../transforms";
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ function importEntriesProcessor(formData: ImportDomainPermsParams): (_entry: Dom
|
|||
// Unset all internal processing keys
|
||||
// and any undefined keys on this entry.
|
||||
Object.entries(entry).forEach(([key, val]: [keyof DomainPerm, any]) => {
|
||||
if (val == undefined || isDomainPermInternalKey(key)) {
|
||||
if (val == undefined || stripOnImport(key)) {
|
||||
delete entry[key];
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -169,6 +169,8 @@ export const gtsApi = createApi({
|
|||
"HTTPHeaderBlocks",
|
||||
"DefaultInteractionPolicies",
|
||||
"InteractionRequest",
|
||||
"DomainPermissionDraft",
|
||||
"DomainPermissionExclude"
|
||||
],
|
||||
endpoints: (build) => ({
|
||||
instanceV1: build.query<InstanceV1, void>({
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import {
|
|||
authorize as oauthAuthorize,
|
||||
} from "../../../redux/oauth";
|
||||
import { RootState } from '../../../redux/store';
|
||||
import { Account } from '../../types/account';
|
||||
|
||||
export interface OauthTokenRequestBody {
|
||||
client_id: string;
|
||||
|
|
@ -58,7 +59,7 @@ const SETTINGS_URL = (getSettingsURL());
|
|||
// https://redux-toolkit.js.org/rtk-query/usage/customizing-queries#performing-multiple-requests-with-a-single-query
|
||||
const extended = gtsApi.injectEndpoints({
|
||||
endpoints: (build) => ({
|
||||
verifyCredentials: build.query<any, void>({
|
||||
verifyCredentials: build.query<Account, void>({
|
||||
providesTags: (_res, error) =>
|
||||
error == undefined ? ["Auth"] : [],
|
||||
async queryFn(_arg, api, _extraOpts, fetchWithBQ) {
|
||||
|
|
|
|||
|
|
@ -53,8 +53,12 @@ export interface Account {
|
|||
url: string,
|
||||
avatar: string,
|
||||
avatar_static: string,
|
||||
avatar_description?: string,
|
||||
avatar_media_id?: string,
|
||||
header: string,
|
||||
header_static: string,
|
||||
header_description?: string,
|
||||
header_media_id?: string,
|
||||
followers_count: number,
|
||||
following_count: number,
|
||||
statuses_count: number,
|
||||
|
|
@ -68,7 +72,7 @@ export interface Account {
|
|||
}
|
||||
|
||||
export interface AccountSource {
|
||||
fields: any[];
|
||||
fields: any;
|
||||
follow_requests_count: number;
|
||||
language: string;
|
||||
note: string;
|
||||
|
|
|
|||
|
|
@ -19,11 +19,12 @@
|
|||
|
||||
import typia from "typia";
|
||||
import { PermType } from "./perm";
|
||||
import { Links } from "parse-link-header";
|
||||
|
||||
export const validateDomainPerms = typia.createValidate<DomainPerm[]>();
|
||||
|
||||
/**
|
||||
* A single domain permission entry (block or allow).
|
||||
* A single domain permission entry (block, allow, draft, ignore).
|
||||
*/
|
||||
export interface DomainPerm {
|
||||
id?: string;
|
||||
|
|
@ -32,11 +33,14 @@ export interface DomainPerm {
|
|||
private_comment?: string;
|
||||
public_comment?: string;
|
||||
created_at?: string;
|
||||
created_by?: string;
|
||||
subscription_id?: string;
|
||||
|
||||
// Internal processing keys; remove
|
||||
// before serdes of domain perm.
|
||||
// Keys that should be stripped before
|
||||
// sending the domain permission (if imported).
|
||||
|
||||
permission_type?: PermType;
|
||||
key?: string;
|
||||
permType?: PermType;
|
||||
suggest?: string;
|
||||
valid?: boolean;
|
||||
checked?: boolean;
|
||||
|
|
@ -53,9 +57,9 @@ export interface MappedDomainPerms {
|
|||
[key: string]: DomainPerm;
|
||||
}
|
||||
|
||||
const domainPermInternalKeys: Set<keyof DomainPerm> = new Set([
|
||||
const domainPermStripOnImport: Set<keyof DomainPerm> = new Set([
|
||||
"key",
|
||||
"permType",
|
||||
"permission_type",
|
||||
"suggest",
|
||||
"valid",
|
||||
"checked",
|
||||
|
|
@ -65,15 +69,14 @@ const domainPermInternalKeys: Set<keyof DomainPerm> = new Set([
|
|||
]);
|
||||
|
||||
/**
|
||||
* Returns true if provided DomainPerm Object key is
|
||||
* "internal"; ie., it's just for our use, and it shouldn't
|
||||
* be serialized to or deserialized from the GtS API.
|
||||
* Returns true if provided DomainPerm Object key is one
|
||||
* that should be stripped when importing a domain permission.
|
||||
*
|
||||
* @param key
|
||||
* @returns
|
||||
*/
|
||||
export function isDomainPermInternalKey(key: keyof DomainPerm) {
|
||||
return domainPermInternalKeys.has(key);
|
||||
export function stripOnImport(key: keyof DomainPerm) {
|
||||
return domainPermStripOnImport.has(key);
|
||||
}
|
||||
|
||||
export interface ImportDomainPermsParams {
|
||||
|
|
@ -94,3 +97,119 @@ export interface ExportDomainPermsParams {
|
|||
action: "export" | "export-file";
|
||||
exportType: "json" | "csv" | "plain";
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for GET to /api/v1/admin/domain_permission_drafts.
|
||||
*/
|
||||
export interface DomainPermDraftSearchParams {
|
||||
/**
|
||||
* Show only drafts created by the given subscription ID.
|
||||
*/
|
||||
subscription_id?: string;
|
||||
/**
|
||||
* Return only drafts that target the given domain.
|
||||
*/
|
||||
domain?: string;
|
||||
/**
|
||||
* Filter on "block" or "allow" type drafts.
|
||||
*/
|
||||
permission_type?: PermType;
|
||||
/**
|
||||
* Return only items *OLDER* than the given max ID (for paging downwards).
|
||||
* The item with the specified ID will not be included in the response.
|
||||
*/
|
||||
max_id?: string;
|
||||
/**
|
||||
* Return only items *NEWER* than the given since ID.
|
||||
* The item with the specified ID will not be included in the response.
|
||||
*/
|
||||
since_id?: string;
|
||||
/**
|
||||
* Return only items immediately *NEWER* than the given min ID (for paging upwards).
|
||||
* The item with the specified ID will not be included in the response.
|
||||
*/
|
||||
min_id?: string;
|
||||
/**
|
||||
* Number of items to return.
|
||||
*/
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export interface DomainPermDraftSearchResp {
|
||||
drafts: DomainPerm[];
|
||||
links: Links | null;
|
||||
}
|
||||
|
||||
export interface DomainPermDraftCreateParams {
|
||||
/**
|
||||
* Domain to create the permission draft for.
|
||||
*/
|
||||
domain: string;
|
||||
/**
|
||||
* Create a draft "allow" or a draft "block".
|
||||
*/
|
||||
permission_type: PermType;
|
||||
/**
|
||||
* Obfuscate the name of the domain when serving it publicly.
|
||||
* Eg., `example.org` becomes something like `ex***e.org`.
|
||||
*/
|
||||
obfuscate?: boolean;
|
||||
/**
|
||||
* Public comment about this domain permission. This will be displayed
|
||||
* alongside the domain permission if you choose to share permissions.
|
||||
*/
|
||||
public_comment?: string;
|
||||
/**
|
||||
* Private comment about this domain permission.
|
||||
* Will only be shown to other admins, so this is a useful way of
|
||||
* internally keeping track of why a certain domain ended up permissioned.
|
||||
*/
|
||||
private_comment?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameters for GET to /api/v1/admin/domain_permission_excludes.
|
||||
*/
|
||||
export interface DomainPermExcludeSearchParams {
|
||||
/**
|
||||
* Return only excludes that target the given domain.
|
||||
*/
|
||||
domain?: string;
|
||||
/**
|
||||
* Return only items *OLDER* than the given max ID (for paging downwards).
|
||||
* The item with the specified ID will not be included in the response.
|
||||
*/
|
||||
max_id?: string;
|
||||
/**
|
||||
* Return only items *NEWER* than the given since ID.
|
||||
* The item with the specified ID will not be included in the response.
|
||||
*/
|
||||
since_id?: string;
|
||||
/**
|
||||
* Return only items immediately *NEWER* than the given min ID (for paging upwards).
|
||||
* The item with the specified ID will not be included in the response.
|
||||
*/
|
||||
min_id?: string;
|
||||
/**
|
||||
* Number of items to return.
|
||||
*/
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export interface DomainPermExcludeSearchResp {
|
||||
excludes: DomainPerm[];
|
||||
links: Links | null;
|
||||
}
|
||||
|
||||
export interface DomainPermExcludeCreateParams {
|
||||
/**
|
||||
* Domain to create the permission exclude for.
|
||||
*/
|
||||
domain: string;
|
||||
/**
|
||||
* Private comment about this domain permission.
|
||||
* Will only be shown to other admins, so this is a useful way of
|
||||
* internally keeping track of why a certain domain ended up permissioned.
|
||||
*/
|
||||
private_comment?: string;
|
||||
}
|
||||
|
|
|
|||
48
web/source/settings/lib/util/formvalidators.ts
Normal file
48
web/source/settings/lib/util/formvalidators.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
GoToSocial
|
||||
Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import isValidDomain from "is-valid-domain";
|
||||
|
||||
/**
|
||||
* Validate the "domain" field of a form.
|
||||
* @param domain
|
||||
* @returns
|
||||
*/
|
||||
export function formDomainValidator(domain: string): string {
|
||||
if (domain.length === 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (domain[domain.length-1] === ".") {
|
||||
return "invalid domain";
|
||||
}
|
||||
|
||||
const valid = isValidDomain(domain, {
|
||||
subdomain: true,
|
||||
wildcard: false,
|
||||
allowUnicode: true,
|
||||
topLevel: false,
|
||||
});
|
||||
|
||||
if (valid) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return "invalid domain";
|
||||
}
|
||||
|
|
@ -41,3 +41,16 @@ export function UseOurInstanceAccount(account: AdminAccount): boolean {
|
|||
|
||||
return !account.domain && account.username == ourDomain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uppercase first letter of given string.
|
||||
*/
|
||||
export function useCapitalize(i?: string): string {
|
||||
return useMemo(() => {
|
||||
if (i === undefined) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return i.charAt(0).toUpperCase() + i.slice(1);
|
||||
}, [i]);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue