diff --git a/tildes/scss/modules/_donation.scss b/tildes/scss/modules/_donation.scss index 826c87a..2bbbbab 100644 --- a/tildes/scss/modules/_donation.scss +++ b/tildes/scss/modules/_donation.scss @@ -5,8 +5,9 @@ display: flex; flex-direction: column; align-items: center; + max-width: $paragraph-max-width; - padding: 0.4rem 0.4rem 0; + padding: 0.4rem; margin: 1rem 0; border: 1px solid; border-color: inherit; diff --git a/tildes/scss/modules/_sidebar.scss b/tildes/scss/modules/_sidebar.scss index 75794d9..61a68bb 100644 --- a/tildes/scss/modules/_sidebar.scss +++ b/tildes/scss/modules/_sidebar.scss @@ -2,10 +2,6 @@ // SPDX-License-Identifier: AGPL-3.0-or-later #sidebar { - p { - margin-bottom: 0.4rem; - } - .btn { width: 100%; } diff --git a/tildes/tildes/templates/financials.jinja2 b/tildes/tildes/templates/financials.jinja2 index 4615d4d..f030f4f 100644 --- a/tildes/tildes/templates/financials.jinja2 +++ b/tildes/tildes/templates/financials.jinja2 @@ -4,6 +4,7 @@ {% extends 'base_no_sidebar.jinja2' %} {% from "macros/utils.jinja2" import format_money %} +{% from "macros/donation_goal.jinja2" import donation_goal %} {% block title %}Tildes financials{% endblock %} @@ -12,6 +13,7 @@ {% block main_heading %}Tildes financials{% endblock %} {% block content %} +
This page is a view into Tildes's financials: operating expenses, income from the various donation methods, and the overall goal for monthly donations. Currently, it only contains data for {{ current_time.strftime("%B %Y") }}, but more historical data will be available eventually.
Amounts on this page are in USD unless otherwise noted. Even though Tildes is a Canadian non-profit, many of its costs and donations are in USD. People from other parts of the world are also generally most familiar with the relative value of USD, so using it makes this info more understandable to everyone.
@@ -22,6 +24,10 @@The current donation goal is {{ format_money(entries["goal"]|sum(attribute="amount")) }} per month.
+{% if financial_data %} + {{ donation_goal(financial_data, current_time) }} +{% endif %} +The actual costs solely to keep Tildes running are much lower than this (see table below), but this represents the amount that I believe will make Tildes truly independently sustainable. It will cover all of the operating costs and also allow me (Deimos) to pay myself a somewhat respectable (but low) salary of about $35,000/year. This goal may not be achievable in the near term, but it is the point where I will be comfortable focusing on Tildes without still needing to find additional outside income.
Please donate—any amount will help get us closer to the goal!
diff --git a/tildes/tildes/templates/home.jinja2 b/tildes/tildes/templates/home.jinja2 index feae5ad..1e342d4 100644 --- a/tildes/tildes/templates/home.jinja2 +++ b/tildes/tildes/templates/home.jinja2 @@ -4,6 +4,7 @@ {% extends 'topic_listing.jinja2' %} {% from 'macros/forms.jinja2' import search_form %} +{% from 'macros/donation_goal.jinja2' import donation_goal %} {% block title_full %}Tildes{% endblock %} @@ -109,35 +110,3 @@ {% endif %} {% endblock %} - -{% macro donation_goal(financial_data, current_time) %} -{{ current_time.strftime("%B %Y") }} donations
- -Tildes is a non-profit site with no ads or investors, funded entirely by donations.
- -Please donate to support its continued development! (more details)
- #}
+{# SPDX-License-Identifier: AGPL-3.0-or-later #}
+
+{% macro donation_goal(financial_data, current_time) %}
+
+ Tildes's progress to sustainability
+
+
+
+ {{ financial_data["goal_percentage"] }}%
+
+
+ {{ current_time.strftime("%B %Y") }} donations
+
+ Tildes is a non-profit site with no ads or investors, funded entirely by donations.
+
+ Please donate to support its continued development! (more details)
+
+{% endmacro %}
diff --git a/tildes/tildes/views/financials.py b/tildes/tildes/views/financials.py
index 624bf2e..0ee33c4 100644
--- a/tildes/tildes/views/financials.py
+++ b/tildes/tildes/views/financials.py
@@ -4,10 +4,13 @@
"""The view for displaying entries in the financials table."""
from collections import defaultdict
-from typing import Dict, List
+from decimal import Decimal
+from typing import Dict, List, Optional
from pyramid.request import Request
from pyramid.view import view_config
+from sqlalchemy import func
+from sqlalchemy.orm.session import Session
from sqlalchemy.sql.expression import text
from tildes.lib.datetime import utc_now
@@ -31,4 +34,33 @@ def get_financials(request: Request) -> dict:
for entry in financial_entries:
entries[entry.entry_type.name.lower()].append(entry)
- return {"entries": entries, "current_time": utc_now()}
+ financial_data = get_financial_data(request.db_session)
+
+ return {
+ "entries": entries,
+ "current_time": utc_now(),
+ "financial_data": financial_data,
+ }
+
+
+def get_financial_data(db_session: Session) -> Optional[Dict[str, Decimal]]:
+ """Return financial data used to render the donation goal box."""
+ # get the total sum for each entry type in the financials table relevant to today
+ financial_totals = (
+ db_session.query(Financials.entry_type, func.sum(Financials.amount))
+ .filter(Financials.date_range.op("@>")(text("CURRENT_DATE")))
+ .group_by(Financials.entry_type)
+ .all()
+ )
+
+ financial_data = {entry[0].name.lower(): entry[1] for entry in financial_totals}
+
+ # if any of the entry types were missing, the data won't be usable
+ if any(key not in financial_data for key in ("expense", "goal", "income")):
+ return None
+
+ financial_data["goal_percentage"] = round(
+ financial_data["income"] / financial_data["goal"] * 100
+ )
+
+ return financial_data
diff --git a/tildes/tildes/views/topic.py b/tildes/tildes/views/topic.py
index 248caac..14d0d4e 100644
--- a/tildes/tildes/views/topic.py
+++ b/tildes/tildes/views/topic.py
@@ -4,9 +4,8 @@
"""Views related to posting/viewing topics and comments on them."""
from collections import namedtuple
-from decimal import Decimal
from difflib import SequenceMatcher
-from typing import Any, Dict, Optional, Union
+from typing import Any, Optional, Union
from marshmallow import missing, ValidationError
from marshmallow.fields import Boolean, String
@@ -15,8 +14,7 @@ from pyramid.renderers import render_to_response
from pyramid.request import Request
from pyramid.response import Response
from pyramid.view import view_config
-from sqlalchemy import cast, func, or_
-from sqlalchemy.orm.session import Session
+from sqlalchemy import cast, or_
from sqlalchemy.sql.expression import any_, desc, text
from sqlalchemy_utils import Ltree
from webargs.pyramidparser import use_kwargs
@@ -31,7 +29,6 @@ from tildes.enums import (
from tildes.lib.database import TagList
from tildes.lib.datetime import SimpleHoursPeriod, utc_now
from tildes.models.comment import Comment, CommentNotification, CommentTree
-from tildes.models.financials import Financials
from tildes.models.group import Group, GroupWikiPage
from tildes.models.log import LogComment, LogTopic
from tildes.models.topic import Topic, TopicSchedule, TopicVisit
@@ -41,6 +38,7 @@ from tildes.schemas.fields import Enum, ShortTimePeriod
from tildes.schemas.listing import TopicListingSchema
from tildes.schemas.topic import TopicSchema
from tildes.views.decorators import rate_limit_view
+from tildes.views.financials import get_financial_data
DefaultSettings = namedtuple("DefaultSettings", ["order", "period"])
@@ -307,7 +305,7 @@ def get_group_topics( # noqa
most_recent_scheduled_topics = None
if is_home_page:
- financial_data = _get_financial_data(request.db_session)
+ financial_data = get_financial_data(request.db_session)
else:
financial_data = None
@@ -560,26 +558,3 @@ def _get_default_settings(
default_period = None
return DefaultSettings(order=default_order, period=default_period)
-
-
-def _get_financial_data(db_session: Session) -> Optional[Dict[str, Decimal]]:
- """Return financial data used to render the donation goal box."""
- # get the total sum for each entry type in the financials table relevant to today
- financial_totals = (
- db_session.query(Financials.entry_type, func.sum(Financials.amount))
- .filter(Financials.date_range.op("@>")(text("CURRENT_DATE")))
- .group_by(Financials.entry_type)
- .all()
- )
-
- financial_data = {entry[0].name.lower(): entry[1] for entry in financial_totals}
-
- # if any of the entry types were missing, the data won't be usable
- if any(key not in financial_data for key in ("expense", "goal", "income")):
- return None
-
- financial_data["goal_percentage"] = round(
- financial_data["income"] / financial_data["goal"] * 100
- )
-
- return financial_data