Skip to content

Commit

Permalink
Closes #606
Browse files Browse the repository at this point in the history
Superusers can now update data hosting quota from the main project settings admin interface.
  • Loading branch information
underbluewaters committed Aug 15, 2023
1 parent 1b6acc3 commit 920f430
Show file tree
Hide file tree
Showing 8 changed files with 380 additions and 0 deletions.
41 changes: 41 additions & 0 deletions packages/api/generated-schema-clean.gql
Original file line number Diff line number Diff line change
Expand Up @@ -8389,6 +8389,12 @@ type Mutation {
"""
input: UpdateCommunityGuidelineByNodeIdInput!
): UpdateCommunityGuidelinePayload
updateDataHostingQuota(
"""
The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields.
"""
input: UpdateDataHostingQuotaInput!
): UpdateDataHostingQuotaPayload

"""Updates a single `DataLayer` using a unique key and a patch."""
updateDataLayer(
Expand Down Expand Up @@ -13934,6 +13940,41 @@ type UpdateCommunityGuidelinePayload {
query: Query
}

"""All input for the `updateDataHostingQuota` mutation."""
input UpdateDataHostingQuotaInput {
"""
An arbitrary string value with no semantic meaning. Will be included in the
payload verbatim. May be used to track mutations by the client.
"""
clientMutationId: String
projectId: Int
quota: BigInt
}

"""The output of our `updateDataHostingQuota` mutation."""
type UpdateDataHostingQuotaPayload {
"""
The exact same `clientMutationId` that was provided in the mutation input,
unchanged and unused. May be used by a client to track mutations.
"""
clientMutationId: String

"""Reads a single `DataSourcesBucket` that is related to this `Project`."""
dataSourcesBucket: DataSourcesBucket
project: Project

"""An edge for our `Project`. May be used by Relay 1."""
projectEdge(
"""The method to use when ordering `Project`."""
orderBy: [ProjectsOrderBy!] = [PRIMARY_KEY_ASC]
): ProjectsEdge

"""
Our root query field type. Allows us to run any query from our mutation payload.
"""
query: Query
}

"""All input for the `updateDataLayerByInteractivitySettingsId` mutation."""
input UpdateDataLayerByInteractivitySettingsIdInput {
"""
Expand Down
41 changes: 41 additions & 0 deletions packages/api/generated-schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -8389,6 +8389,12 @@ type Mutation {
"""
input: UpdateCommunityGuidelineByNodeIdInput!
): UpdateCommunityGuidelinePayload
updateDataHostingQuota(
"""
The exclusive input argument for this mutation. An object type, make sure to see documentation for this object’s fields.
"""
input: UpdateDataHostingQuotaInput!
): UpdateDataHostingQuotaPayload

"""Updates a single `DataLayer` using a unique key and a patch."""
updateDataLayer(
Expand Down Expand Up @@ -13934,6 +13940,41 @@ type UpdateCommunityGuidelinePayload {
query: Query
}

"""All input for the `updateDataHostingQuota` mutation."""
input UpdateDataHostingQuotaInput {
"""
An arbitrary string value with no semantic meaning. Will be included in the
payload verbatim. May be used to track mutations by the client.
"""
clientMutationId: String
projectId: Int
quota: BigInt
}

"""The output of our `updateDataHostingQuota` mutation."""
type UpdateDataHostingQuotaPayload {
"""
The exact same `clientMutationId` that was provided in the mutation input,
unchanged and unused. May be used by a client to track mutations.
"""
clientMutationId: String

"""Reads a single `DataSourcesBucket` that is related to this `Project`."""
dataSourcesBucket: DataSourcesBucket
project: Project

"""An edge for our `Project`. May be used by Relay 1."""
projectEdge(
"""The method to use when ordering `Project`."""
orderBy: [ProjectsOrderBy!] = [PRIMARY_KEY_ASC]
): ProjectsEdge

"""
Our root query field type. Allows us to run any query from our mutation payload.
"""
query: Query
}

"""All input for the `updateDataLayerByInteractivitySettingsId` mutation."""
input UpdateDataLayerByInteractivitySettingsIdInput {
"""
Expand Down
16 changes: 16 additions & 0 deletions packages/api/migrations/committed/000272.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--! Previous: sha1:6d0e0ecb4eb8cbce2e864dce288208def90f03d1
--! Hash: sha1:e3f0e93b74596af2758d245047060587ded98a81

-- Enter migration here
create or replace function update_data_hosting_quota(project_id int, quota bigint)
returns projects
language sql
security definer
as $$
update projects
set data_hosting_quota = quota
where id = project_id
returning *;
$$;

grant execute on function update_data_hosting_quota(int, bigint) to seasketch_superuser;
22 changes: 22 additions & 0 deletions packages/api/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -12538,6 +12538,20 @@ CREATE FUNCTION public.update_basemap_offline_tile_settings("projectId" integer,
$$;


--
-- Name: update_data_hosting_quota(integer, bigint); Type: FUNCTION; Schema: public; Owner: -
--

CREATE FUNCTION public.update_data_hosting_quota(project_id integer, quota bigint) RETURNS public.projects
LANGUAGE sql SECURITY DEFINER
AS $$
update projects
set data_hosting_quota = quota
where id = project_id
returning *;
$$;


--
-- Name: update_mapbox_secret_key(integer, text); Type: FUNCTION; Schema: public; Owner: -
--
Expand Down Expand Up @@ -27990,6 +28004,14 @@ REVOKE ALL ON FUNCTION public.update_basemap_offline_tile_settings("projectId" i
GRANT ALL ON FUNCTION public.update_basemap_offline_tile_settings("projectId" integer, "basemapId" integer, use_default boolean, "maxZ" integer, "maxShorelineZ" integer) TO seasketch_user;


--
-- Name: FUNCTION update_data_hosting_quota(project_id integer, quota bigint); Type: ACL; Schema: public; Owner: -
--

REVOKE ALL ON FUNCTION public.update_data_hosting_quota(project_id integer, quota bigint) FROM PUBLIC;
GRANT ALL ON FUNCTION public.update_data_hosting_quota(project_id integer, quota bigint) TO seasketch_superuser;


--
-- Name: FUNCTION update_mapbox_secret_key(project_id integer, secret text); Type: ACL; Schema: public; Owner: -
--
Expand Down
83 changes: 83 additions & 0 deletions packages/client/src/admin/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {
useMapboxApiKeysQuery,
UpdateSecretKeyDocument,
useUpdateOfflineEnabledMutation,
useProjectHostingQuotaQuery,
useUpdateDataHostingQuotaMutation,
} from "../generated/graphql";
import ProjectAutosaveInput from "./ProjectAutosaveInput";
import { useDropzone } from "react-dropzone";
Expand Down Expand Up @@ -46,6 +48,7 @@ import SupportedLanguagesSettings from "./SupportedLanguagesSettings";
import getSlug from "../getSlug";
import { TranslateIcon } from "@heroicons/react/outline";
import TranslatedPropControl from "../components/TranslatedPropControl";
import bytes from "bytes";

export default function Settings() {
const { data } = useCurrentProjectMetadata();
Expand Down Expand Up @@ -713,8 +716,27 @@ function SuperUserSettings() {
const { t, i18n } = useTranslation("admin");
const { slug } = useParams<{ slug: string }>();
const [isFeatured, setIsFeatured] = useState<boolean | null>(null);
const onError = useGlobalErrorHandler();
const { data, loading, error } = useCurrentProjectMetadata();
const [mutate, mutationState] = useUpdateProjectSettingsMutation();
const quotaQuery = useProjectHostingQuotaQuery({
variables: { slug },
onError,
});

const [updateQuota, updateQuotaState] = useUpdateDataHostingQuotaMutation({
optimisticResponse: (data) => {
return {
__typename: "Mutation",
updateProjectById: {
__typename: "Project",
id: data.projectId,
dataHostingQuota: data.quota,
},
};
},
});

const [updateOfflineEnabled, updateOfflineEnabledState] =
useUpdateOfflineEnabledMutation();

Expand Down Expand Up @@ -800,6 +822,67 @@ function SuperUserSettings() {
"If enabled, project administrators will have access to experimental offline survey functionality. Otherwise these options will be hidden."
)}
/>
<InputBlock
input={
<select
className="text-sm rounded py-1"
value={(
quotaQuery.data?.projectBySlug?.dataHostingQuota || 0
).toString()}
onChange={(e) => {
const quota = parseInt(e.target.value);
updateQuota({
variables: {
projectId: data!.project!.id,
quota,
},
});
}}
>
<option value={bytes("500 MB").toString()}>500 MB</option>
<option value={bytes("1 GB").toString()}>1 GB</option>
<option value={bytes("2 GB").toString()}>2 GB</option>
<option value={bytes("5 GB").toString()}>5 GB</option>
<option value={bytes("10 GB").toString()}>10 GB</option>
<option value={bytes("20 GB").toString()}>20 GB</option>
</select>
}
title={
<>
<span>{t("Data Hosting Quota")}</span>
{quotaQuery.data?.projectBySlug?.dataHostingQuota ? (
<span
className={` ml-5 ${
quotaQuery.data.projectBySlug.dataHostingQuota *
0.9 <=
quotaQuery.data.projectBySlug.dataHostingQuotaUsed
? "text-red-800"
: "text-gray-500"
}`}
>
{bytes(
parseInt(
quotaQuery.data.projectBySlug.dataHostingQuotaUsed
),
{
unit: "GB",
}
) +
" / " +
bytes(
parseInt(
quotaQuery.data.projectBySlug.dataHostingQuota
)
) +
" used"}
</span>
) : null}
</>
}
description={t(
"Amount of spatial data that can be uploaded to this project. We limit this amount initially to prevent abuse and to identify important projects."
)}
/>
</div>
</div>
</form>
Expand Down
Loading

0 comments on commit 920f430

Please sign in to comment.