Compare commits
4 Commits
dd012cf3bf
...
a0b3750737
| Author | SHA1 | Date |
|---|---|---|
|
|
a0b3750737 | |
|
|
30301c8a7f | |
|
|
7b470a7f6f | |
|
|
03aeb707f2 |
40
README.md
40
README.md
|
|
@ -56,20 +56,18 @@ For announcements of new releases and cutting-edge beta versions, please subscri
|
|||
topic. If you'd like to test the iOS app, join [TestFlight](https://testflight.apple.com/join/P1fFnAm9). For Android betas,
|
||||
join Discord/Matrix (I'll eventually make a testing channel in Google Play).
|
||||
|
||||
## Contributing
|
||||
I welcome any contributions. Just create a PR or an issue. For larger features/ideas, please reach out
|
||||
on Discord/Matrix first to see if I'd accept them. To contribute code, check out the [build instructions](https://ntfy.sh/docs/develop/)
|
||||
for the server and the Android app. Or, if you'd like to help translate 🇩🇪 🇺🇸 🇧🇬, you can start immediately in
|
||||
[Hosted Weblate](https://hosted.weblate.org/projects/ntfy/).
|
||||
|
||||
<a href="https://hosted.weblate.org/engage/ntfy/">
|
||||
<img src="https://hosted.weblate.org/widgets/ntfy/-/multi-blue.svg" alt="Translation status" />
|
||||
</a>
|
||||
|
||||
## Sponsors
|
||||
I have just very recently started accepting donations via [GitHub Sponsors](https://github.com/sponsors/binwiederhier),
|
||||
and [Liberapay](https://liberapay.com/ntfy). I would be humbled if you helped me carry the server and developer
|
||||
account costs. Even small donations are very much appreciated. A big fat **Thank You** to the folks who have sponsored ntfy in the past, or are still sponsoring ntfy:
|
||||
If you'd like to support the ntfy maintainers, please consider donating to [GitHub Sponsors](https://github.com/sponsors/binwiederhier) or
|
||||
and [Liberapay](https://liberapay.com/ntfy). We would be humbled if you helped carry the server and developer
|
||||
account costs. Even small donations are very much appreciated.
|
||||
|
||||
Thank you to our commercial sponsors, who help keep the service running and the development going:
|
||||
|
||||
<a href="https://m.do.co/c/442b929528db"><img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="201px"></a>
|
||||
|
||||
<a href="https://www.magicbell.com/?utm_source=ntfy"><img src="assets/sponsors/magicbell.png" width="180px"></a>
|
||||
|
||||
And a big fat **Thank You** to the individuals who have sponsored ntfy in the past, or are still sponsoring ntfy:
|
||||
|
||||
<a href="https://github.com/neutralinsomniac"><img src="https://github.com/neutralinsomniac.png" width="40px" /></a>
|
||||
<a href="https://github.com/aspyct"><img src="https://github.com/aspyct.png" width="40px" /></a>
|
||||
|
|
@ -210,13 +208,21 @@ account costs. Even small donations are very much appreciated. A big fat **Thank
|
|||
<a href="https://github.com/user8446"><img src="https://github.com/user8446.png" width="40px" /></a>
|
||||
<a href="https://github.com/cdf-eagles"><img src="https://github.com/cdf-eagles.png" width="40px" /></a>
|
||||
|
||||
I'd also like to thank JetBrains for their awesome [IntelliJ IDEA](https://www.jetbrains.com/idea/),
|
||||
and [DigitalOcean](https://m.do.co/c/442b929528db) (*referral link*) for supporting the project:
|
||||
## Contributing
|
||||
I welcome any contributions. Just create a PR or an issue. For larger features/ideas, please reach out
|
||||
on Discord/Matrix first to see if I'd accept them. To contribute code, check out the [build instructions](https://ntfy.sh/docs/develop/)
|
||||
for the server and the Android app. Or, if you'd like to help translate 🇩🇪 🇺🇸 🇧🇬, you can start immediately in
|
||||
[Hosted Weblate](https://hosted.weblate.org/projects/ntfy/).
|
||||
|
||||
<a href="https://m.do.co/c/442b929528db"><img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="201px"></a>
|
||||
<a href="https://hosted.weblate.org/engage/ntfy/">
|
||||
<img src="https://hosted.weblate.org/widgets/ntfy/-/multi-blue.svg" alt="Translation status" />
|
||||
</a>
|
||||
|
||||
## Code of Conduct
|
||||
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
|
||||
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for
|
||||
everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity
|
||||
and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste,
|
||||
color, religion, or sexual identity and orientation.
|
||||
|
||||
**We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.**
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -62,6 +62,7 @@ var flagsServe = append(
|
|||
altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-signup", Aliases: []string{"enable_signup"}, EnvVars: []string{"NTFY_ENABLE_SIGNUP"}, Value: false, Usage: "allows users to sign up via the web app, or API"}),
|
||||
altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-login", Aliases: []string{"enable_login"}, EnvVars: []string{"NTFY_ENABLE_LOGIN"}, Value: false, Usage: "allows users to log in via the web app, or API"}),
|
||||
altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-reservations", Aliases: []string{"enable_reservations"}, EnvVars: []string{"NTFY_ENABLE_RESERVATIONS"}, Value: false, Usage: "allows users to reserve topics (if their tier allows it)"}),
|
||||
altsrc.NewBoolFlag(&cli.BoolFlag{Name: "require-login", Aliases: []string{"require_login"}, EnvVars: []string{"NTFY_REQUIRE_LOGIN"}, Value: false, Usage: "all actions via the web app requires a login"}),
|
||||
altsrc.NewStringFlag(&cli.StringFlag{Name: "upstream-base-url", Aliases: []string{"upstream_base_url"}, EnvVars: []string{"NTFY_UPSTREAM_BASE_URL"}, Value: "", Usage: "forward poll request to an upstream server, this is needed for iOS push notifications for self-hosted servers"}),
|
||||
altsrc.NewStringFlag(&cli.StringFlag{Name: "upstream-access-token", Aliases: []string{"upstream_access_token"}, EnvVars: []string{"NTFY_UPSTREAM_ACCESS_TOKEN"}, Value: "", Usage: "access token to use for the upstream server; needed only if upstream rate limits are exceeded or upstream server requires auth"}),
|
||||
altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-sender-addr", Aliases: []string{"smtp_sender_addr"}, EnvVars: []string{"NTFY_SMTP_SENDER_ADDR"}, Usage: "SMTP server address (host:port) for outgoing emails"}),
|
||||
|
|
|
|||
|
|
@ -1481,6 +1481,7 @@ variable before running the `ntfy` command (e.g. `export NTFY_LISTEN_HTTP=:80`).
|
|||
| `enable-signup` | `NTFY_ENABLE_SIGNUP` | *boolean* (`true` or `false`) | `false` | Allows users to sign up via the web app, or API |
|
||||
| `enable-login` | `NTFY_ENABLE_LOGIN` | *boolean* (`true` or `false`) | `false` | Allows users to log in via the web app, or API |
|
||||
| `enable-reservations` | `NTFY_ENABLE_RESERVATIONS` | *boolean* (`true` or `false`) | `false` | Allows users to reserve topics (if their tier allows it) |
|
||||
| `require-login` | `NTFY_REQUIRE_LOGIN` | *boolean* (`true` or `false`) | `false` | All actions via the web app require a login |
|
||||
| `stripe-secret-key` | `NTFY_STRIPE_SECRET_KEY` | *string* | - | Payments: Key used for the Stripe API communication, this enables payments |
|
||||
| `stripe-webhook-key` | `NTFY_STRIPE_WEBHOOK_KEY` | *string* | - | Payments: Key required to validate the authenticity of incoming webhooks from Stripe |
|
||||
| `billing-contact` | `NTFY_BILLING_CONTACT` | *email address* or *website* | - | Payments: Email or website displayed in Upgrade dialog as a billing contact |
|
||||
|
|
|
|||
|
|
@ -243,6 +243,7 @@ func NewConfig() *Config {
|
|||
EnableSignup: false,
|
||||
EnableLogin: false,
|
||||
EnableReservations: false,
|
||||
RequireLogin: false,
|
||||
AccessControlAllowOrigin: "*",
|
||||
Version: "",
|
||||
WebPushPrivateKey: "",
|
||||
|
|
|
|||
|
|
@ -586,6 +586,7 @@ func (s *Server) handleWebConfig(w http.ResponseWriter, _ *http.Request, _ *visi
|
|||
EnableCalls: s.config.TwilioAccount != "",
|
||||
EnableEmails: s.config.SMTPSenderFrom != "",
|
||||
EnableReservations: s.config.EnableReservations,
|
||||
ReuqireLogin: s.config.RequireLogin,
|
||||
EnableWebPush: s.config.WebPushPublicKey != "",
|
||||
BillingContact: s.config.BillingContact,
|
||||
WebPushPublicKey: s.config.WebPushPublicKey,
|
||||
|
|
|
|||
|
|
@ -228,10 +228,12 @@
|
|||
# - enable-signup allows users to sign up via the web app, or API
|
||||
# - enable-login allows users to log in via the web app, or API
|
||||
# - enable-reservations allows users to reserve topics (if their tier allows it)
|
||||
# - require-login all user actions via the web app require a login
|
||||
#
|
||||
# enable-signup: false
|
||||
# enable-login: false
|
||||
# enable-reservations: false
|
||||
# require-login: false
|
||||
|
||||
# Server URL of a Firebase/APNS-connected ntfy server (likely "https://ntfy.sh").
|
||||
#
|
||||
|
|
|
|||
|
|
@ -409,6 +409,7 @@ type apiConfigResponse struct {
|
|||
EnableEmails bool `json:"enable_emails"`
|
||||
EnableReservations bool `json:"enable_reservations"`
|
||||
EnableWebPush bool `json:"enable_web_push"`
|
||||
RequireLogin bool `json:"require_login"`
|
||||
BillingContact string `json:"billing_contact"`
|
||||
WebPushPublicKey string `json:"web_push_public_key"`
|
||||
DisallowedTopics []string `json:"disallowed_topics"`
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@
|
|||
"notifications_none_for_any_description": "To send notifications to a topic, simply PUT or POST to the topic URL. Here's an example using one of your topics.",
|
||||
"notifications_no_subscriptions_title": "It looks like you don't have any subscriptions yet.",
|
||||
"notifications_no_subscriptions_description": "Click the \"{{linktext}}\" link to create or subscribe to a topic. After that, you can send messages via PUT or POST and you'll receive notifications here.",
|
||||
"notifications_no_subscriptions_login_title": "This page requires a Login.",
|
||||
"notifications_no_subscriptions_login_description": "Click \"{{linktext}}\" to login into your account.",
|
||||
"notifications_example": "Example",
|
||||
"notifications_more_details": "For more information, check out the <websiteLink>website</websiteLink> or <docsLink>documentation</docsLink>.",
|
||||
"display_name_dialog_title": "Change display name",
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ const NavList = (props) => {
|
|||
{showNotificationContextNotSupportedBox && <NotificationContextNotSupportedAlert />}
|
||||
{showNotificationIOSInstallRequired && <NotificationIOSInstallRequiredAlert />}
|
||||
{alertVisible && <Divider />}
|
||||
{!showSubscriptionsList && (
|
||||
{!showSubscriptionsList && (session.exists() || !config.require_login) && (
|
||||
<ListItemButton onClick={() => navigate(routes.app)} selected={location.pathname === config.app_root}>
|
||||
<ListItemIcon>
|
||||
<ChatBubble />
|
||||
|
|
@ -164,30 +164,36 @@ const NavList = (props) => {
|
|||
<ListItemText primary={t("nav_button_account")} />
|
||||
</ListItemButton>
|
||||
)}
|
||||
{session.exists() || !config.require_login && (
|
||||
<ListItemButton onClick={() => navigate(routes.settings)} selected={location.pathname === routes.settings}>
|
||||
<ListItemIcon>
|
||||
<SettingsIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t("nav_button_settings")} />
|
||||
</ListItemButton>
|
||||
)}
|
||||
<ListItemButton onClick={() => openUrl("/docs")}>
|
||||
<ListItemIcon>
|
||||
<ArticleIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t("nav_button_documentation")} />
|
||||
</ListItemButton>
|
||||
{session.exists() || !config.require_login && (
|
||||
<ListItemButton onClick={() => props.onPublishMessageClick()}>
|
||||
<ListItemIcon>
|
||||
<Send />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t("nav_button_publish_message")} />
|
||||
</ListItemButton>
|
||||
)}
|
||||
{session.exists() || !config.require_login && (
|
||||
<ListItemButton onClick={() => setSubscribeDialogOpen(true)}>
|
||||
<ListItemIcon>
|
||||
<AddIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={t("nav_button_subscribe")} />
|
||||
</ListItemButton>
|
||||
)}
|
||||
{showUpgradeBanner && (
|
||||
// The text background gradient didn't seem to do well with switching between light/dark mode,
|
||||
// So adding a `key` forces React to replace the entire component when the theme changes
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import priority5 from "../img/priority-5.svg";
|
|||
import logoOutline from "../img/ntfy-outline.svg";
|
||||
import AttachmentIcon from "./AttachmentIcon";
|
||||
import { useAutoSubscribe } from "./hooks";
|
||||
import session from "../app/Session";
|
||||
|
||||
const priorityFiles = {
|
||||
1: priority1,
|
||||
|
|
@ -635,12 +636,16 @@ const NoSubscriptions = () => {
|
|||
<Typography variant="h5" align="center" sx={{ paddingBottom: 1 }}>
|
||||
<img src={logoOutline} height="64" width="64" alt={t("action_bar_logo_alt")} />
|
||||
<br />
|
||||
{t("notifications_no_subscriptions_title")}
|
||||
{!session.exists() && !config.require_login && t("notifications_no_subscriptions_title")}
|
||||
{!session.exists() && config.require_login && t("notifications_no_subscriptions_login_title")}
|
||||
</Typography>
|
||||
<Paragraph>
|
||||
{t("notifications_no_subscriptions_description", {
|
||||
{!session.exists() && !config.require_login && t("notifications_no_subscriptions_description", {
|
||||
linktext: t("nav_button_subscribe"),
|
||||
})}
|
||||
{!session.exists() && config.require_login && t("notifications_no_subscriptions_login_description", {
|
||||
linktext: t("action_bar_sign_in"),
|
||||
})}
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<ForMoreDetails />
|
||||
|
|
|
|||
|
|
@ -65,16 +65,22 @@ const maybeUpdateAccountSettings = async (payload) => {
|
|||
}
|
||||
};
|
||||
|
||||
const Preferences = () => (
|
||||
<Container maxWidth="md" sx={{ marginTop: 3, marginBottom: 3 }}>
|
||||
<Stack spacing={3}>
|
||||
<Notifications />
|
||||
<Reservations />
|
||||
<Users />
|
||||
<Appearance />
|
||||
</Stack>
|
||||
</Container>
|
||||
);
|
||||
const Preferences = () => {
|
||||
if (!session.exists() or !config.requireLogin) {
|
||||
window.location.href = routes.app;
|
||||
return <></>;
|
||||
}
|
||||
return (
|
||||
<Container maxWidth="md" sx={{ marginTop: 3, marginBottom: 3 }}>
|
||||
<Stack spacing={3}>
|
||||
<Notifications />
|
||||
<Reservations />
|
||||
<Users />
|
||||
<Appearance />
|
||||
</Stack>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
const Notifications = () => {
|
||||
const { t } = useTranslation();
|
||||
|
|
|
|||
Loading…
Reference in New Issue