satellite/console,web/satellite: configure whether free user can invite
This change adds a flag to the satellite config indicating whether free tier users should be able to send project invitations. Change-Id: I9c030c88dbef136ba4a9bf2d8f027a8dcd77fd33
This commit is contained in:
parent
e5fd061e70
commit
a6222afdd0
@ -22,6 +22,7 @@ type Config struct {
|
||||
FailedLoginPenalty float64 `help:"incremental duration of penalty for failed login attempts in minutes" default:"2.0"`
|
||||
ProjectInvitationExpiration time.Duration `help:"duration that project member invitations are valid for" default:"168h"`
|
||||
UnregisteredInviteEmailsEnabled bool `help:"indicates whether invitation emails can be sent to unregistered email addresses" default:"false"`
|
||||
FreeTierInvitesEnabled bool `help:"indicates whether free tier users can send project invitations" default:"false"`
|
||||
UserBalanceForUpgrade int64 `help:"amount of base units of US micro dollars needed to upgrade user's tier status" default:"10000000"`
|
||||
PlacementEdgeURLOverrides PlacementEdgeURLOverrides `help:"placement-specific edge service URL overrides in the format {\"placementID\": {\"authService\": \"...\", \"publicLinksharing\": \"...\", \"internalLinksharing\": \"...\"}, \"placementID2\": ...}"`
|
||||
BlockExplorerURL string `help:"url of the transaction block explorer" default:"https://etherscan.io/"`
|
||||
|
@ -52,6 +52,7 @@ type FrontendConfig struct {
|
||||
ObjectBrowserPaginationEnabled bool `json:"objectBrowserPaginationEnabled"`
|
||||
BillingFeaturesEnabled bool `json:"billingFeaturesEnabled"`
|
||||
UnregisteredInviteEmailsEnabled bool `json:"unregisteredInviteEmailsEnabled"`
|
||||
FreeTierInvitesEnabled bool `json:"freeTierInvitesEnabled"`
|
||||
}
|
||||
|
||||
// Satellites is a configuration value that contains a list of satellite names and addresses.
|
||||
|
@ -753,6 +753,7 @@ func (server *Server) frontendConfigHandler(w http.ResponseWriter, r *http.Reque
|
||||
ObjectBrowserPaginationEnabled: server.config.ObjectBrowserPaginationEnabled,
|
||||
BillingFeaturesEnabled: server.config.BillingFeaturesEnabled,
|
||||
UnregisteredInviteEmailsEnabled: server.config.UnregisteredInviteEmailsEnabled,
|
||||
FreeTierInvitesEnabled: server.config.FreeTierInvitesEnabled,
|
||||
}
|
||||
|
||||
err := json.NewEncoder(w).Encode(&cfg)
|
||||
|
@ -3775,7 +3775,7 @@ func (s *Service) inviteProjectMembers(ctx context.Context, sender *User, projec
|
||||
}
|
||||
projectID = isMember.project.ID
|
||||
|
||||
if !sender.PaidTier {
|
||||
if !(s.config.FreeTierInvitesEnabled || sender.PaidTier) {
|
||||
return nil, ErrNotPaidTier.New(paidTierInviteErrMsg)
|
||||
}
|
||||
|
||||
|
3
scripts/testdata/satellite-config.yaml.lock
vendored
3
scripts/testdata/satellite-config.yaml.lock
vendored
@ -280,6 +280,9 @@ compensation.withheld-percents: 75,75,75,50,50,50,25,25,25,0,0,0,0,0,0
|
||||
# allow domains to embed the satellite in a frame, space separated
|
||||
# console.frame-ancestors: tardigrade.io storj.io
|
||||
|
||||
# indicates whether free tier users can send project invitations
|
||||
# console.free-tier-invites-enabled: false
|
||||
|
||||
# server address of the front-end app
|
||||
# console.frontend-address: :10200
|
||||
|
||||
|
@ -8,21 +8,21 @@
|
||||
<div class="modal__header">
|
||||
<TeamMembersIcon />
|
||||
<h1 class="modal__header__title">
|
||||
{{ isPaidTier ? 'Invite team member' : 'Upgrade to Pro' }}
|
||||
{{ needsUpgrade ? 'Upgrade to Pro' : 'Invite team member' }}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<p class="modal__info">
|
||||
<template v-if="isPaidTier">
|
||||
Add a team member to contribute to this project.
|
||||
<template v-if="needsUpgrade">
|
||||
Upgrade now to unlock collaboration and bring your team together in this project.
|
||||
</template>
|
||||
<template v-else>
|
||||
Upgrade now to unlock collaboration and bring your team together in this project.
|
||||
Add a team member to contribute to this project.
|
||||
</template>
|
||||
</p>
|
||||
|
||||
<VInput
|
||||
v-if="isPaidTier"
|
||||
v-if="!needsUpgrade"
|
||||
class="modal__input"
|
||||
label="Email"
|
||||
height="38px"
|
||||
@ -43,14 +43,14 @@
|
||||
:on-press="closeModal"
|
||||
/>
|
||||
<VButton
|
||||
:label="isPaidTier ? 'Invite' : 'Upgrade'"
|
||||
:label="needsUpgrade ? 'Upgrade' : 'Invite'"
|
||||
height="48px"
|
||||
font-size="14px"
|
||||
border-radius="10px"
|
||||
:on-press="onPrimaryClick"
|
||||
:is-disabled="!!formError || isLoading"
|
||||
>
|
||||
<template v-if="!isPaidTier" #icon-right>
|
||||
<template v-if="needsUpgrade" #icon-right>
|
||||
<ArrowIcon />
|
||||
</template>
|
||||
</VButton>
|
||||
@ -101,7 +101,7 @@ const email = ref<string>('');
|
||||
* or a message describing the validation error.
|
||||
*/
|
||||
const formError = computed<string | boolean>(() => {
|
||||
if (!isPaidTier.value) return false;
|
||||
if (needsUpgrade.value) return false;
|
||||
if (!email.value) return true;
|
||||
if (email.value.toLocaleLowerCase() === usersStore.state.user.email.toLowerCase()) {
|
||||
return `You can't add yourself to the project.`;
|
||||
@ -113,17 +113,17 @@ const formError = computed<string | boolean>(() => {
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns user's paid tier status from store.
|
||||
* Returns whether the user should upgrade to pro tier before inviting.
|
||||
*/
|
||||
const isPaidTier = computed<boolean>(() => {
|
||||
return usersStore.state.user.paidTier;
|
||||
const needsUpgrade = computed<boolean>(() => {
|
||||
return !(usersStore.state.user.paidTier || configStore.state.config.freeTierInvitesEnabled);
|
||||
});
|
||||
|
||||
/**
|
||||
* Handles primary button click.
|
||||
*/
|
||||
async function onPrimaryClick(): Promise<void> {
|
||||
if (!isPaidTier.value) {
|
||||
if (needsUpgrade.value) {
|
||||
appStore.updateActiveModal(MODALS.upgradeAccount);
|
||||
return;
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ export class FrontendConfig {
|
||||
objectBrowserPaginationEnabled: boolean;
|
||||
billingFeaturesEnabled: boolean;
|
||||
unregisteredInviteEmailsEnabled: boolean;
|
||||
freeTierInvitesEnabled: boolean;
|
||||
}
|
||||
|
||||
export class MultiCaptchaConfig {
|
||||
|
@ -2,6 +2,8 @@
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<v-overlay v-model="model" persistent />
|
||||
|
||||
<v-dialog
|
||||
:model-value="model && !isUpgradeDialogShown"
|
||||
width="auto"
|
||||
@ -18,7 +20,7 @@
|
||||
</template>
|
||||
|
||||
<v-card-title class="font-weight-bold">
|
||||
{{ isPaidTier ? 'Add Member' : 'Upgrade to Pro' }}
|
||||
{{ needsUpgrade ? 'Upgrade to Pro' : 'Add Member' }}
|
||||
</v-card-title>
|
||||
|
||||
<template #append>
|
||||
@ -37,7 +39,10 @@
|
||||
|
||||
<v-form v-model="valid" class="pa-7 pb-4" @submit.prevent="onPrimaryClick">
|
||||
<v-row>
|
||||
<template v-if="isPaidTier">
|
||||
<v-col v-if="needsUpgrade">
|
||||
Upgrade now to unlock collaboration and bring your team together in this project.
|
||||
</v-col>
|
||||
<template v-else>
|
||||
<v-col cols="12">
|
||||
<p class="mb-5">Invite a team member to join you in this project.</p>
|
||||
<v-alert
|
||||
@ -63,9 +68,6 @@
|
||||
/>
|
||||
</v-col>
|
||||
</template>
|
||||
<v-col v-else>
|
||||
Upgrade now to unlock collaboration and bring your team together in this project.
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-form>
|
||||
|
||||
@ -82,10 +84,10 @@
|
||||
variant="flat"
|
||||
block
|
||||
:loading="isLoading"
|
||||
:append-icon="!isPaidTier ? 'mdi-arrow-right' : undefined"
|
||||
:append-icon="needsUpgrade ? 'mdi-arrow-right' : undefined"
|
||||
@click="onPrimaryClick"
|
||||
>
|
||||
{{ isPaidTier ? 'Send Invite' : 'Upgrade' }}
|
||||
{{ needsUpgrade ? 'Upgrade' : 'Send Invite' }}
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
@ -98,12 +100,6 @@
|
||||
:model-value="model && isUpgradeDialogShown"
|
||||
@update:model-value="v => model = isUpgradeDialogShown = v"
|
||||
/>
|
||||
|
||||
<teleport to="body">
|
||||
<v-fade-transition>
|
||||
<div v-show="model" class="v-overlay__scrim custom-scrim" />
|
||||
</v-fade-transition>
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@ -121,7 +117,7 @@ import {
|
||||
VAlert,
|
||||
VTextField,
|
||||
VCardActions,
|
||||
VFadeTransition,
|
||||
VOverlay,
|
||||
} from 'vuetify/components';
|
||||
|
||||
import { RequiredRule, ValidationRule } from '@poc/types/common';
|
||||
@ -167,17 +163,17 @@ const emailRules: ValidationRule<string>[] = [
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns user's paid tier status from store.
|
||||
* Returns whether the user should upgrade to pro tier before inviting.
|
||||
*/
|
||||
const isPaidTier = computed<boolean>(() => {
|
||||
return usersStore.state.user.paidTier;
|
||||
const needsUpgrade = computed<boolean>(() => {
|
||||
return !(usersStore.state.user.paidTier || configStore.state.config.freeTierInvitesEnabled);
|
||||
});
|
||||
|
||||
/**
|
||||
* Handles primary button click.
|
||||
*/
|
||||
async function onPrimaryClick(): Promise<void> {
|
||||
if (!isPaidTier.value) {
|
||||
if (needsUpgrade.value) {
|
||||
isUpgradeDialogShown.value = true;
|
||||
return;
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
// See LICENSE for copying information.
|
||||
|
||||
<template>
|
||||
<v-overlay v-model="model" persistent />
|
||||
|
||||
<v-dialog
|
||||
:model-value="model && !isUpgradeDialogShown"
|
||||
width="410px"
|
||||
@ -113,16 +115,10 @@
|
||||
:model-value="model && isUpgradeDialogShown"
|
||||
@update:model-value="v => model = isUpgradeDialogShown = v"
|
||||
/>
|
||||
|
||||
<teleport to="body">
|
||||
<v-fade-transition>
|
||||
<div v-show="model" class="v-overlay__scrim custom-scrim" />
|
||||
</v-fade-transition>
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, Teleport } from 'vue';
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import {
|
||||
VDialog,
|
||||
@ -136,7 +132,7 @@ import {
|
||||
VRow,
|
||||
VCol,
|
||||
VTextField,
|
||||
VFadeTransition,
|
||||
VOverlay,
|
||||
} from 'vuetify/components';
|
||||
|
||||
import { RequiredRule, ValidationRule } from '@poc/types/common';
|
||||
|
@ -122,10 +122,6 @@ html {
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.custom-scrim {
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
// Align the checkboxes in the tables
|
||||
.v-selection-control {
|
||||
contain: inherit;
|
||||
|
Loading…
Reference in New Issue
Block a user