Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding permission blocker for free tier #6001

Merged
merged 9 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion admin/src/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,35 @@ document.addEventListener("DOMContentLoaded", async () => {
const appConfigSchema = schemaByCategories({
hubs: toml.parse(await fetch("/hubs/schema.toml").then(r => r.text()))
});

const appConfigSchemaCopy = { ...appConfigSchema };

/**
* Note: we are removing the "images" and "theme" tab from the app settings tabs and making a new page,
* these pages are intended to be blocked in free tier.
*/
delete appConfigSchema.images;
delete appConfigSchema.theme;

const BrandRoute = (
<Route
path="/brand"
render={props => <AppConfigEditor {...props} schema={{ images: appConfigSchemaCopy.images }} />}
/>
);

const themeRoute = (
<Route
path="/themes"
render={props => <AppConfigEditor {...props} schema={{ theme: appConfigSchemaCopy.theme }} />}
/>
);

const appConfigRoute = (
<Route path="/app-settings" render={props => <AppConfigEditor {...props} schema={appConfigSchema} />} />
);
customRoutes.push(appConfigRoute);

customRoutes.push(appConfigRoute, themeRoute, BrandRoute);
} catch (e) {
console.error("Could not initialize app config.", e);
}
Expand Down
57 changes: 57 additions & 0 deletions admin/src/react-components/admin-menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import SettingsIcon from "@material-ui/icons/Settings";
import Collapse from "@material-ui/core/Collapse";
import { getServiceDisplayName } from "../utils/ita";
import configs from "../utils/configs";
import { hasPaidFeature } from "../utils/feature_flags";
import HubsLogo from "../assets/images/hubs_logo.png";

const mapStateToProps = state => ({
Expand Down Expand Up @@ -185,6 +186,36 @@ class Menu extends Component {
</ListItemIcon>
<ListItemText className={this.props.classes.text} primary="App Settings" />
</ListItem>

{hasPaidFeature() && (
<>
{/* IMAGE SETTING */}
<ListItem
className={classNames(this.props.classes.item, this.props.classes.nested)}
component={NavLink}
key="brand"
to="/brand"
>
<ListItemIcon className={this.props.classes.icon}>
<ViewIcon />
</ListItemIcon>
<ListItemText className={this.props.classes.text} primary="Brand" />
</ListItem>

{/* THEMES */}
<ListItem
className={classNames(this.props.classes.item, this.props.classes.nested)}
component={NavLink}
key="themes"
to="/themes"
>
<ListItemIcon className={this.props.classes.icon}>
<ViewIcon />
</ListItemIcon>
<ListItemText className={this.props.classes.text} primary="Themes" />
</ListItem>
</>
)}
</List>
</Collapse>
</List>
Expand Down Expand Up @@ -248,6 +279,32 @@ class Menu extends Component {
</ListItemIcon>
<ListItemText className={this.props.classes.text} primary="App Settings" />
</ListItem>

<ListItem
className={classNames(this.props.classes.item, this.props.classes.nested)}
component={NavLink}
key="brand"
to="/brand"
>
<ListItemIcon className={this.props.classes.icon}>
<ViewIcon />
</ListItemIcon>
<ListItemText className={this.props.classes.text} primary="Brand" />
</ListItem>

{/* THEMES */}
<ListItem
className={classNames(this.props.classes.item, this.props.classes.nested)}
component={NavLink}
key="themes"
to="/themes"
>
<ListItemIcon className={this.props.classes.icon}>
<ViewIcon />
</ListItemIcon>
<ListItemText className={this.props.classes.text} primary="Themes" />
</ListItem>

<ListItem
className={classNames(this.props.classes.item, this.props.classes.nested)}
component={NavLink}
Expand Down
21 changes: 12 additions & 9 deletions admin/src/react-components/pages/system-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import CardSection from "../shared/CardSection";
import { Icon } from "@mozilla/lilypad-ui";
import { DiscordIcon, BookIcon, QuestionIcon, GithubIcon } from "../shared/icons";
import Card from "../shared/Card";
import { hasPaidFeature } from "../../utils/feature_flags";

const styles = withCommonStyles(() => ({}));

Expand Down Expand Up @@ -107,14 +108,16 @@ const SystemEditorComponent = ({ classes }) => {
<section className="mb-40">
<h3 className="heading-sm mb-28">Customize the look of your hub</h3>

<CardSection
className="mb-20"
ctaCallback={() => {
window.location.href = "#/app-settings";
}}
cta="apply my window"
body="Apply your branding to the hub’s website and lobby."
/>
{hasPaidFeature() && (
<CardSection
className="mb-20"
ctaCallback={() => {
window.location.href = "#/brand";
}}
cta="Add my Logo"
body="Apply your branding to the hub’s website and lobby."
/>
)}

<CardSection
className="mb-20"
Expand Down Expand Up @@ -292,7 +295,7 @@ const SystemEditorComponent = ({ classes }) => {
>
Hubs Documentation
</a>{" "}
Contain a Getting Started guide and other resources.
contains a Getting Started guide and other resources.
</p>
</div>

Expand Down
68 changes: 65 additions & 3 deletions admin/src/react-components/service-editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import React, { Component } from "react";
import { withStyles } from "@material-ui/core/styles";
import CircularProgress from "@material-ui/core/CircularProgress";
import RefreshIcon from "@material-ui/icons/Refresh";
import ExpandIcon from "./shared/icons/ExpandIcon";
import PictureIcon from "./shared/icons/PictureIcon";
import Card from "@material-ui/core/Card";
import Tabs from "@material-ui/core/Tabs";
import Tab from "@material-ui/core/Tab";
Expand Down Expand Up @@ -408,6 +410,8 @@ class ConfigurationEditor extends Component {
switch (category) {
case "theme":
return this.renderThemeSection(schema.theme, config);
case "images":
return this.renderImagesSection(schema.images, config);
default:
return this.renderTree(schema, category, config);
}
Expand All @@ -434,16 +438,17 @@ class ConfigurationEditor extends Component {
<h3 className="heading-sm mb-24 mt-40">Theme Data</h3>
<p className="body-md">
This section contains the code which generates the available themes a user can choose from when in your
hub&#39;s rooms (More &gt; Preferences &gt; Misc &gt; Theme). More information about{" "}
hub&#39;s rooms (More &gt; Preferences &gt; Misc &gt; Theme).More information about customizing your hubs&#39;
themes can be found in our{" "}
<a
href="https://hubs.mozilla.com/docs/hubs-cloud-customizing-themes.html"
target="_blank"
rel="noopener noreferrer"
className="link"
>
customising you hubs&#39; themes
documentation pages
</a>{" "}
can be found in our documentation pages.
.
</p>
{getInput(configurables[2])}
<div>
Expand All @@ -464,6 +469,63 @@ class ConfigurationEditor extends Component {
);
}

/**
* Images AKA Brand Tab Section
*/
renderImagesSection(images, config) {
const configurables = this.getFilteredDescriptors(images);
const getInput = ([path, descriptor]) => this.renderConfigurable(path, descriptor, getConfigValue(config, path));

const AdditionalInfo = ({ size, format }) => {
return (
<div className="flex-align-items-center">
<ExpandIcon />
<span className="ml-10 mr-20">{size}</span>
<PictureIcon />
<span className="ml-10">{format}</span>
</div>
);
};

return (
<form onSubmit={this.onSubmit.bind(this)}>
<h3 className="heading-sm mb-24">Hub</h3>

{/* HUB LOGO */}
{getInput(configurables[0])}
<AdditionalInfo size="250px x 250px" format="JPG, GIF, PNG, SVG" />

{/* HUB LOGO DARK MODE */}
{getInput(configurables[1])}
<AdditionalInfo size="250px x 250px" format="JPG, GIF, PNG, SVG" />

{/* FAVICON */}
{getInput(configurables[2])}
<AdditionalInfo size="96px x 96px" format="JPG, GIF, PNG" />

<h3 className="heading-sm mb-24 mt-40">Hub Home Page</h3>

{/* HOMEPAGE IMAGE */}
{getInput(configurables[3])}
<AdditionalInfo size="1000px x 1000px" format="JPG, GIF, PNG, SVG" />

{/* COMPANY LOGO */}
{getInput(configurables[4])}
<AdditionalInfo size="250px x 250px" format="JPG, GIF, PNG, SVG" />

<h3 className="heading-sm mb-24 mt-40">Sharing and Social Media</h3>

{/* SHORTCUT ICON */}
{getInput(configurables[5])}
<AdditionalInfo size="512px x 512px" format="JPG, GIF, PNG" />

{/* SOCIAL MEDIA CARD */}
{getInput(configurables[6])}
<AdditionalInfo size="1024px x 576px (max)" format="JPG, GIF, PNG" />
</form>
);
}

/**
* General Render Tree
*/
Expand Down
2 changes: 1 addition & 1 deletion admin/src/react-components/shared/CardSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type CardSectionPropsT = {
const CardSection = ({ cta, ctaLabel, ctaCallback, body, className }: CardSectionPropsT) => {
return (
<div className={`card_section_wrapper ${className}`}>
<div className="flex-align-items-center max-w-600-px">
<div className="flex-align-items-center max-w-800-px">
<div>
<Icon name="arrow-right-circle" size={30} classProp="mr-20" />
</div>
Expand Down
38 changes: 38 additions & 0 deletions admin/src/react-components/shared/icons/ExpandIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from "react";

const ExpandIcon = () => {
return (
<svg width="14" height="14" viewBox="0 0 17 16" fill="none">
<path
d="M2.19982 14.2666L6.88436 9.61791"
stroke="#5A5A5A"
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M14.6845 2.01144L9.99991 6.66016"
stroke="#5A5A5A"
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M5.19604 15.2781L1.19607 15.2627L1.21142 11.2628"
stroke="#5A5A5A"
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M11.6882 1L15.6882 1.01535L15.6729 5.01532"
stroke="#5A5A5A"
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
);
};

export default ExpandIcon;
31 changes: 31 additions & 0 deletions admin/src/react-components/shared/icons/PictureIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from "react";

const PictureIcon = () => {
return (
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
<path
d="M12.6667 2H3.33333C2.59695 2 2 2.59695 2 3.33333V12.6667C2 13.403 2.59695 14 3.33333 14H12.6667C13.403 14 14 13.403 14 12.6667V3.33333C14 2.59695 13.403 2 12.6667 2Z"
stroke="#5A5A5A"
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M5.66675 6.66663C6.21903 6.66663 6.66675 6.21891 6.66675 5.66663C6.66675 5.11434 6.21903 4.66663 5.66675 4.66663C5.11446 4.66663 4.66675 5.11434 4.66675 5.66663C4.66675 6.21891 5.11446 6.66663 5.66675 6.66663Z"
stroke="#5A5A5A"
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M13.9999 9.99996L10.6666 6.66663L3.33325 14"
stroke="#5A5A5A"
stroke-width="1.33333"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
);
};

export default PictureIcon;
10 changes: 6 additions & 4 deletions admin/src/utils/configs.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// Read configs from global variable if available, otherwise use the process.env injected from build.
const configs = {};

["RETICULUM_SERVER", "POSTGREST_SERVER", "ITA_SERVER", "CONFIGURABLE_SERVICES", "CORS_PROXY_SERVER"].forEach(x => {
const el = document.querySelector(`meta[name='env:${x.toLowerCase()}']`);
configs[x] = el ? el.getAttribute("content") : process.env[x];
});
["RETICULUM_SERVER", "POSTGREST_SERVER", "ITA_SERVER", "TIER", "CONFIGURABLE_SERVICES", "CORS_PROXY_SERVER"].forEach(
x => {
const el = document.querySelector(`meta[name='env:${x.toLowerCase()}']`);
configs[x] = el ? el.getAttribute("content") : process.env[x];
}
);

// Custom clients do not use <meta> tags for passing data, so if reticulum_server meta tag exists, it is not a custom client
const hasReticulumServerMetaTag = !!document.querySelector("meta[name='env:reticulum_server']");
Expand Down
10 changes: 10 additions & 0 deletions admin/src/utils/feature_flags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import configs from "../utils/configs";
import { PaidTiers } from "../../types";

export function hasPaidFeature(): boolean {
// If the user is not a turkey user then no need to check.
if (configs.ITA_SERVER != "turkey") return true;

const authorizedTiers: PaidTiers[] = ["p1", "b1"];
return authorizedTiers.includes(configs.TIER);
}
2 changes: 0 additions & 2 deletions admin/src/utils/ita.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,6 @@ function getCategoryDescription(category, provider) {
return "Text that you can change.";
case "features":
return "Features that you can toggle.";
case "images":
return "Replace images in the app.";
case "colors":
return "Replace colors in the app.";
case "links":
Expand Down
9 changes: 9 additions & 0 deletions admin/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ export type ReticulumMetaT = {
repo: ReticulumRepoT;
};

/**
* p0 : FREE TIER
* p1 : STANDARD TIER
* b1: BUSINESS TIER
*/
export type TiersT = "p0" | "p1" | "b1";

export type PaidTiers = "p1" | "b1";

export type ReticulumRepoT = {
accounts: {
any: boolean;
Expand Down
Loading