1
0
mirror of https://github.com/privacyguides/privacyguides.org.git synced 2025-07-02 01:32:41 +00:00

feat!: Add list of monthly/annual members to website (#2927)

Signed-off-by: blacklight447 <niek@privacyguides.org>
Signed-off-by: Daniel Gray <dngray@privacyguides.org>
Signed-off-by: Freddy <freddy@privacyguides.org>
This commit is contained in:
2025-03-05 19:00:27 -06:00
parent c2cfb0fce6
commit 1c8afe6a15
15 changed files with 304 additions and 62 deletions

View File

@ -72,6 +72,8 @@ jobs:
continue-on-error: false
privileged: ${{ fromJSON(needs.metadata.outputs.privileged) }}
strict: true
secrets:
RO_DISCOURSE_API_KEY: ${{ secrets.RO_DISCOURSE_API_KEY }}
build_i18n:
if: ${{ contains(github.event.pull_request.labels.*.name, 'ci:build i18n') }}

View File

@ -30,6 +30,9 @@ on:
cache:
type: boolean
default: true
secrets:
RO_DISCOURSE_API_KEY:
required: false
permissions:
contents: read
@ -172,23 +175,31 @@ jobs:
sudo apt install pngquant
echo "EXTRA_FLAGS=""$EXTRA_FLAGS" --cmd=mkdocs"" >> "$GITHUB_ENV"
- name: Generate Donating Members List
continue-on-error: true
env:
DISCOURSE_API_KEY: ${{ secrets.RO_DISCOURSE_API_KEY }}
run: |
pip install requests
python generate-members.py > includes/members.md
- name: Build Website
run: |
eval ./run.sh --build --lang=${{ inputs.lang }} "$EXTRA_FLAGS"
- name: Run index-generation.sh for top posts
- name: Run generate-topics.sh for top posts
if: inputs.lang == 'en'
run: |
bash index-generation.sh \
bash generate-topics.sh \
--source='https://discuss.privacyguides.net/top.json?period=weekly' \
--tag="top posts" \
--destination="./site/en/index.html" \
--count=3
- name: Run index-generation.sh for latest posts
- name: Run generate-topics.sh for latest posts
if: inputs.lang == 'en'
run: |
bash index-generation.sh \
bash generate-topics.sh \
--source='https://discuss.privacyguides.net/latest.json' \
--tag="latest posts" \
--destination="./site/en/index.html" \
@ -259,6 +270,14 @@ jobs:
path: site-${{ inputs.config }}-${{ inputs.lang }}.tar.gz
retention-days: 1
- name: Upload members list
uses: actions/upload-artifact@v4
if: inputs.lang == 'en'
with:
name: members.md
path: includes/members.md
retention-days: 1
offline_package:
if: inputs.config == 'offline' && inputs.lang == 'en'
needs: build

View File

@ -63,6 +63,8 @@ jobs:
context: production
continue-on-error: false
cache: false
secrets:
RO_DISCOURSE_API_KEY: ${{ secrets.RO_DISCOURSE_API_KEY }}
build_blog:
needs: submodule

View File

@ -55,17 +55,17 @@ jobs:
source: /en/index.html
target: ./site/en/
- name: Run index-generation.sh for top posts
- name: Run generate-topics.sh for top posts
run: |
bash index-generation.sh \
bash generate-topics.sh \
--source='https://discuss.privacyguides.net/top.json?period=weekly' \
--tag="top posts" \
--destination="./site/en/index.html" \
--count=3
- name: Run index-generation.sh for latest posts
- name: Run generate-topics.sh for latest posts
run: |
bash index-generation.sh \
bash generate-topics.sh \
--source='https://discuss.privacyguides.net/latest.json' \
--tag="latest posts" \
--destination="./site/en/index.html" \

3
.gitignore vendored
View File

@ -23,3 +23,6 @@ node_modules
.venv
.env
.mkdocs-insiders-*
# Automatically generated
includes/members.md

View File

@ -3,38 +3,110 @@ title: Donate
description: The charitable mission of Privacy Guides relies on contributions from visitors like yourself. Anything you can do to support the project is hugely appreciated.
---
<!-- markdownlint-disable MD036 -->
Donate to Privacy Guides and support our mission to defend digital rights and spread the word about mass surveillance programs and other daily privacy invasions. You can help Privacy Guides researchers, activists, and maintainers create informative content, host private digital services, and protect privacy rights at a time when the world needs it most.
Support our mission to defend digital rights and spread the word about mass surveillance programs and other daily privacy invasions. You can help Privacy Guides researchers, activists, and maintainers create informative content, host private digital services, and protect privacy rights at a time when the world needs it most.
Privacy Guides has been a nonstop effort for over 5 years to stay up to date with the world of cybersecurity and privacy, and to promote the benefits of privacy overall. This is a **non-profit, community-driven** project that would not be possible without the generous support of all our [contributors](contributors.md).
[:material-heart:{ .pg-red } Become a Member](https://donate.magicgrants.org/privacyguides/membership){ class="md-button md-button--primary" }
[:material-hand-coin: Make a Donation](https://donate.magicgrants.org/privacyguides/donate/privacyguides){ class="md-button md-button--primary" }
## Donate
<small markdown>
MAGIC Grants is our fiscal host, and their custom, open-source donation platform allows you to donate to our project with **Monero**, **Bitcoin**, or **debit/credit card**.
MAGIC Grants is our fiscal host, and their custom, open-source donation platform allows you to donate to our project with **Monero**, **Bitcoin**, or **debit/credit card**. You can also donate using [:simple-github: GitHub Sponsors](https://github.com/sponsors/privacyguides).
[:material-heart:{ .pg-red } Donate](https://donate.magicgrants.org/privacyguides){ class="md-button md-button--primary" }
[Sponsor on GitHub](https://github.com/sponsors/privacyguides){ class="md-button" }
</small>
Donating with Monero will maximize your donation by lowering our transaction fees while simultaneously [preserving your privacy](../cryptocurrency.md), win-win! You can also donate to us via GitHub Sponsors if you prefer, or if you would like to publicize your support. GitHub does not charge us any fees if you donate as an individual, but may charge us fees if you donate with a GitHub organization, if this is a concern for you.
## Foundations & Organizations
## How We Use Donations
=== "Current Supporters"
Privacy Guides is a **non-profit** project. Your donation will go to a [dedicated fund](https://magicgrants.org/funds/privacy_guides) within [MAGIC Grants](https://magicgrants.org), a 501(c)(3) organization and our fiscal host. The funds will **only** be used for this project specifically.
Thank you to these organizations who significantly support Privacy Guides. (1)
{ .annotate }
1. Please contact <info@magicgrants.org> to inquire about giving. Privacy Guides reserves the right to rescind the membership of those who are unaligned with our mission or organization at any time. Organizational members have no ability to influence what content is recommended on the Privacy Guides website. Learn more about our [donation acceptance policy](donation-acceptance-policy.md).
<div class="mdx-specialthanks" markdown>
[![Power Up Privacy]](https://powerupprivacy.com){ rel=nofollow target=_blank title="Power Up Privacy" }
[![DeleteMe]](https://joindeleteme.com){ rel=nofollow target=_blank title="DeleteMe" }
[Power Up Privacy]: ../assets/img/donors/power-up-privacy.webp
[DeleteMe]: ../assets/img/donors/deleteme.webp
</div>
=== "Past Supporters"
Thank you to these organizations who have substantially supported our project in the past.
- [Safing](https://safing.io){ rel=nofollow target=_blank }: 2019 2021
## Active Members
Privacy Guides would not be possible without these individuals who generously donate on a monthly or yearly basis. (1)
{ .annotate }
1. If you [become a member](https://donate.magicgrants.org/privacyguides/membership) and [link your donation](https://discuss.privacyguides.net/t/getting-your-member-flair-on-the-forum/25453) to your forum account, you're automatically added here with a link to your profile and avatar to show your support for Privacy Guides. If you link your forum account but don't set your flair or title, you'll be a silent +1. You can change your visibility any time. This chart is updated upon each website release.
<div class="mdx-donors" data-mdx-component="donors">
<div class="mdx-donors__list">
--8<-- "includes/members.md"
</div>
</div>
<small markdown>
This is a list of our **active** [members](https://donate.magicgrants.org/privacyguides/membership), plus donors on GitHub, who have chosen to make their donation public. Hundreds more have donated in the past or privately, and their support is hugely appreciated as well.
</small>
## Merchandise
You can support us and share your passion for privacy by buying our merchandise from HelloTux.
[Buy on HelloTux.com](https://hellotux.com/privacyguides){ class="md-button" }
## Non-Financial Support
It takes a lot of [people](contributors.md) and [work](https://github.com/privacyguides/privacyguides.org/pulse/monthly) to keep Privacy Guides up to date and spread the word about privacy and mass surveillance. If you're looking for other ways to help out, consider getting involved by [editing the site](https://github.com/privacyguides/privacyguides.org), [joining our forum](https://discuss.privacyguides.net), or [contributing translations](https://crowdin.com/project/privacyguides).
## FAQ
### What is an organizational membership?
Organizational membership to Privacy Guides is open to any company, private foundation, or organization that donates at least $5,000 per year. While Privacy Guides does not endorse private companies or their products, we're grateful for their contributions. Your donation may be tax-deductible, and we will provide you with a receipt.
You can become an organizational member by reaching out to <info@magicgrants.org> for more information.
### How are organizational members recognized?
Organizational members that choose to be recognized publicly are included in our organizational members section (above), and occasionally at other opportunities where appropriate. Organizational member links include the `rel="nofollow"` attribute: We adopted this policy to screen out potential abuse of our program and site to raise the rank of third parties in search algorithms. Unfortunately, this is a growing problem for nonprofits. This was a complex decision since we know many of the sincere supporters behind these companies, but we decided that it was the best choice for us.
Organizational members have no ability to influence what content is recommended on the Privacy Guides website. Learn more about our [donation acceptance policy](donation-acceptance-policy.md).
### What is an active membership?
Your monthly or yearly membership sustains Privacy Guides's services and public activism for privacy and cybersecurity year round. If you become a member, we will recognize your support here on our website, our community forum, and occasionally in other areas like our videos if you choose to make your membership publicly known.
Our membership program is brand new, and we are still exploring other ways that we can share a token of our appreciation with you, while maintaining sustainable and ethical boundaries. Stay tuned!
### How does Privacy Guides use donations?
Privacy Guides has been a nonstop effort for over 5 years to stay up to date with the world of cybersecurity and privacy, and to promote the benefits of privacy overall. This is a **non-profit, community-driven** project that would not be possible without the generous support of all our [contributors](contributors.md), in addition to our regularly donating members above.
Your donation go to a [dedicated fund](https://magicgrants.org/funds/privacy_guides) within [MAGIC Grants](https://magicgrants.org), a 501(c)(3) organization and our fiscal host. The funds will **only** be used for this project specifically.
You may qualify for a tax deduction. When you donate to us [here](https://donate.magicgrants.org/privacyguides) with cryptocurrency or card you have the option to receive a receipt from MAGIC Grants for this purpose. If you have questions about other transactions please email <info@magicgrants.org>.
We use donations for a variety of purposes, including:
**Web Hosting**
: Traffic to this website uses hundreds of gigabytes of data per month, we use a variety of service providers to keep up with this traffic.
**Payroll**
: We are endeavoring to [hire](jobs.md) full-time journalists and writers to review products and create more educational content on a regular basis.
: We have journalists, writers, and video creators on payroll to review products and create more educational content on a regular basis. This is a significant expense, and we are only able to create our quantity of content with your support.
**Domain Registrations**
**Web Hosting and Infrastructure**
: We have a few domain names like `privacyguides.org` which cost us around $10 yearly to maintain their registration.
: Traffic to this website uses hundreds of gigabytes of data per month; we use a variety of service providers to keep up with this traffic.
**Online Services**
@ -46,14 +118,4 @@ We use donations for a variety of purposes, including:
Thank you to all those who support our mission! :material-heart:{ .pg-red }
We strictly **cannot** use donations to support political campaigns/candidates or attempt to influence legislation. Earnings also will **not** inure to the benefit of any private shareholder or individual.
## Merchandise
Another option to support us is by buying our merchandise from HelloTux. We get a small commission for each item sold, and you get a quality product to show for it.
[Buy on HelloTux.com](https://hellotux.com/privacyguides){ class="md-button" }
## Non-Financial Support
It takes a lot of [people](contributors.md) and [work](https://github.com/privacyguides/privacyguides.org/pulse/monthly) to keep Privacy Guides up to date and spread the word about privacy and mass surveillance. If you're looking for other ways to help out, consider getting involved by [editing the site](https://github.com/privacyguides/privacyguides.org), [joining our forum](https://discuss.privacyguides.net), or [contributing translations](https://crowdin.com/project/privacyguides).
We strictly **do not** use donations to support political campaigns/candidates or attempt to influence legislation. Earnings will **not** inure to the benefit of any private shareholder or individual.

93
generate-members.py Normal file
View File

@ -0,0 +1,93 @@
import requests
import os
GITHUB_API_URL = "https://api.github.com/graphql"
GITHUB_TOKEN = os.getenv("GH_TOKEN")
ORG_NAME = "privacyguides"
# Fetch members from the API
members_api_url = "https://discuss.privacyguides.net/g/members/members.json?offset=0&order=added_at&asc=true"
headers = {
"Api-Key": os.getenv("DISCOURSE_API_KEY"),
"Api-Username": "system"
}
members_response = requests.get(members_api_url, headers=headers)
members_data = members_response.json()
if 'members' not in members_data:
raise KeyError("Response JSON does not contain 'members' key")
members = members_data['members']
private_members_count = 0
html_output = ""
for member in members:
flair_name = member.get('flair_name')
title = member.get('title')
if flair_name == "members" or title == "Member":
username = member['username']
avatar_template = member['avatar_template']
avatar_url = f"https://discuss.privacyguides.net{avatar_template.replace('{size}', '128')}"
profile_url = f"https://discuss.privacyguides.net/u/{username}"
html_output += f'<a href="{profile_url}" target="_blank" title="@{username}" class="mdx-donors__item"><img loading="lazy" src="{avatar_url}"></a>'
else:
private_members_count += 1
# print(html_output)
query = """
{
organization(login: "%s") {
sponsorshipsAsMaintainer(first: 100) {
nodes {
sponsorEntity {
... on User {
login
avatarUrl
url
}
... on Organization {
login
avatarUrl
url
}
}
createdAt
}
}
}
}
""" % ORG_NAME
headers = {
"Authorization": f"Bearer {GITHUB_TOKEN}",
"Content-Type": "application/json"
}
response = requests.post(GITHUB_API_URL, json={'query': query}, headers=headers)
data = response.json()
if 'errors' in data:
raise Exception(f"GraphQL query failed with errors: {data['errors']}")
if 'data' not in data:
raise KeyError(f"Response JSON does not contain 'data' key: {data}")
sponsors = data['data']['organization']['sponsorshipsAsMaintainer']['nodes']
# Sort sponsors by the date they began their sponsorship
sponsors.sort(key=lambda x: x['createdAt'])
for sponsor in sponsors:
sponsor_entity = sponsor['sponsorEntity']
login = sponsor_entity['login']
avatar_url = sponsor_entity['avatarUrl']
url = sponsor_entity['url']
html_output += f'<a href="{url}" title="@{login}" rel="ugc nofollow" target="_blank" class="mdx-donors__item"><img loading="lazy" src="{avatar_url}&size=120"></a>'
private_members_count += 6
# Append the count of private members
if private_members_count > 0:
html_output += f'<a href="https://donate.magicgrants.org/privacyguides" class="mdx-donors__item mdx-donors__item--private">+{private_members_count}</a>'
print(html_output)

View File

@ -287,11 +287,11 @@ theme:
- search.highlight
extra_css:
- assets/stylesheets/extra.css?v=20240802
- assets/stylesheets/extra.css?v=20250306
extra_javascript:
- path: assets/javascripts/randomize-element.js?v=20240801
- path: assets/javascripts/randomize-element.js?v=20250306
defer: true
- path: assets/javascripts/feedback.js?v=20240801
- path: assets/javascripts/feedback.js?v=20250306
defer: true
watch:
@ -450,13 +450,15 @@ nav:
- "device-integrity.md"
- !ENV [NAV_BLOG, "Articles"]: "/articles/"
- !ENV [NAV_VIDEOS, "Videos"]: /videos/
- !ENV [NAV_FORUM, "Forum"]:
!ENV [NAV_FORUM_LINK, "https://discuss.privacyguides.net/"]
- !ENV [NAV_ABOUT, "About"]:
- "about.md"
- "about/donate.md"
- !ENV [NAV_ABOUT_TEAM_MEMBERS, "Team Members"]:
https://discuss.privacyguides.net/u?group=team&order=solutions&period=all
- "about/criteria.md"
- !ENV [NAV_ABOUT_POLICIES, "Policies"]:
- "about/criteria.md"
- "about/donation-acceptance-policy.md"
- "about/executive-policy.md"
- "privacy.md"
@ -477,9 +479,6 @@ nav:
- "meta/uploading-images.md"
- "meta/git-recommendations.md"
- "meta/commit-messages.md"
- !ENV [NAV_DONATE, "Donate"]: https://donate.magicgrants.org/privacyguides
- !ENV [NAV_FORUM, "Forum"]:
!ENV [NAV_FORUM_LINK, "https://discuss.privacyguides.net/"]
validation:
nav:

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -527,3 +527,75 @@ path[d="M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-
list-style-type: disc;
padding-inline-start: 1em;
}
/* Donations */
.md-typeset .mdx-specialthanks p {
margin:2em 0;
text-align:center
}
.md-typeset .mdx-specialthanks img {
height:3.25rem
}
.md-typeset .mdx-specialthanks p:last-child {
display:flex;
flex-wrap:wrap;
justify-content:center
}
.md-typeset .mdx-specialthanks p:last-child>a {
display:block;
flex-shrink:0
}
.md-typeset .mdx-donors__list {
margin:2em 0
}
.md-typeset .mdx-donors__list:after {
clear:both;
content:"";
display:block
}
[dir=ltr] .md-typeset .mdx-donors__item {
float:left
}
[dir=rtl] .md-typeset .mdx-donors__item {
float:right
}
.md-typeset .mdx-donors__item {
border-radius:100%;
display:block;
height:3rem;
margin:.2rem;
overflow:hidden;
transform:scale(1);
transition:color 125ms,transform 125ms;
width:3rem
}
.md-typeset .mdx-donors__item:focus,
.md-typeset .mdx-donors__item:hover {
transform:scale(1.1)
}
.md-typeset .mdx-donors__item:focus img,
.md-typeset .mdx-donors__item:hover img {
filter:grayscale(0)
}
.md-typeset .mdx-donors__item--private {
background:var(--md-default-fg-color--lightest);
color:var(--md-default-fg-color--lighter);
font-size:.8rem;
font-weight:700;
line-height:2.9rem;
text-align:center
}
.md-typeset .mdx-donors__item img {
display:block;
filter:grayscale(100%) opacity(75%);
height:auto;
transition:filter 125ms;
width:100%
}
.md-typeset .mdx-donors-button {
font-weight:400
}
.md-typeset .mdx-donors-count,
.md-typeset .mdx-donors-total {
font-weight:700
}

View File

@ -92,23 +92,3 @@
</script>
{% endif %}
{% endblock %}
{% if config.theme.language == "en" and config.extra.context == "production" %}
{% block announce %}
<span>
<strong>We don't run ads, we don't use affiliate links, and we don't have paywalls.</strong> We rely on our readers to build this community and spread the word.<br>
If you've received $3 worth of knowledge here, please donate today if you're able to. It really helps.
<a href="https://donate.magicgrants.org/privacyguides" target="_blank">
<span class="twemoji pg-red">
{% include ".icons/material/heart.svg" %}
</span>
<span class="pg-red">
Donate now
</span>
<span class="twemoji pg-red">
{% include ".icons/material/arrow-right.svg" %}
</span>
</a>
</span>
{% endblock %}
{% endif %}

View File

@ -0,0 +1,8 @@
<div class="md-header__option">
<div class="">
{% set icon = "material/heart" %}
<a href="/en/about/donate/" class="md-header__button md-icon pg-red" title="Donate">
{% include ".icons/" ~ icon ~ ".svg" %}
</a>
</div>
</div>

View File

@ -136,6 +136,8 @@
{% if not config.theme.palette is mapping %}
{% include "partials/javascripts/palette.html" %}
{% endif %}
{% include "partials/donate.html" %}
</nav>
<!-- Navigation tabs (sticky) -->