25e88996c1236eb2c30a08088ad5cff2080996b3 — Drew DeVault 22 days ago c2e5cf8
Require payment to submit builds, phase one

Phase two will simply involve removing that temporary if statement after
a notice period.
M buildsrht/blueprints/api.py => buildsrht/blueprints/api.py +5 -1
@@ 5,7 5,7 @@ from srht.database import db
from srht.flask import csrf_bypass
from srht.validation import Validation
from srht.oauth import oauth, current_token
from buildsrht.runner import queue_build
from buildsrht.runner import queue_build, requires_payment
from buildsrht.types import Artifact, Job, JobStatus, Task, JobGroup
from buildsrht.types import Trigger, TriggerType, TriggerCondition
from buildsrht.manifest import Manifest

@@ 28,6 28,10 @@ def jobs_GET():
def jobs_POST():
    valid = Validation(request)
    if requires_payment(current_token.user):
        valid.error("Payment is required to submit build jobs. Set up billing at https://meta.sr.ht/billing/initial")
        return valid.response, 402

    _manifest = valid.require("manifest", cls=str)
    max_len = Job.manifest.prop.columns[0].type.length
    valid.expect(not _manifest or len(_manifest) < max_len,

M buildsrht/blueprints/jobs.py => buildsrht/blueprints/jobs.py +8 -2
@@ 11,7 11,7 @@ from srht.validation import Validation
from buildsrht.types import Job, JobStatus, Task, TaskStatus, User
from buildsrht.manifest import Manifest
from buildsrht.rss import generate_feed
from buildsrht.runner import queue_build
from buildsrht.runner import queue_build, requires_payment
from buildsrht.search import apply_search
from jinja2 import Markup, escape
import sqlalchemy as sa

@@ 172,7 172,13 @@ def submit_GET():
    manifest = session.get("manifest")
    if manifest:
        del session["manifest"]
    return render_template("submit.html", manifest=manifest)
    status = 200
    payment_required = requires_payment(current_user)
    if payment_required:
        status = 402
    return render_template("submit.html",
            payment_required=payment_required), status


M buildsrht/runner.py => buildsrht/runner.py +16 -0
@@ 1,8 1,12 @@
import json
from celery import Celery
from datetime import datetime
from srht.config import cfg
from srht.database import db
from srht.email import send_email
from srht.oauth import UserType

allow_free = cfg("builds.sr.ht", "allow-free", default="no") == "yes"

runner = Celery('builds', broker=cfg("builds.sr.ht", "redis"), config_source={

@@ 26,6 30,18 @@ def queue_build(job, manifest):
        run_build.delay(job.id, manifest.to_dict())

def requires_payment(user):
    if allow_free:
        return False
    # Temporary:
    if user.created < datetime(year=2021, month=5, day=1):
        return False
    return user.user_type not in [

def run_build(job_id, manifest):
    pass # see worker/context.go

M buildsrht/templates/submit.html => buildsrht/templates/submit.html +22 -0
@@ 11,6 11,27 @@
{% endblock %}
{% block content %} 
{% if payment_required %}
<section class="row">
  <div class="col-md-8 offset-md-2">
    <h3>Payment required</h3>
    You must have a paid sourcehut account to submit jobs to builds.sr.ht.
    Financial aid is available for users who need it.
    <div style="margin-bottom: 1rem">
        href="{{get_origin('meta.sr.ht', external=True)}}/billing/initial"
        class="btn btn-primary"
      >Proceed to billing setup {{icon('caret-right')}}</a>
    <h4>Other payment-related resources</h4>
      <li><a href="https://man.sr.ht/billing-faq.md">Billing FAQ</a></li>
      <li><a href="https://man.sr.ht/ops/builds.sr.ht-migration.md">builds.sr.ht background information</a></li>
{% else %}
<section class="row">
  <div class="col-md-4">

@@ 60,6 81,7 @@
{% endif %}
{% endblock %}
{% block scripts %}
<script src="/static/codemirror.js"></script>

M config.example.ini => config.example.ini +3 -0
@@ 97,6 97,9 @@ oauth-client-secret=
# /usr/bin/runner-shell for workers.
# If master and worker are on the same system set to /usr/bin/runner-shell
# Set to "yes" to allow nonpaying users to submit builds

# These config options are only necessary for systems running a build runner