~sircmpwn/names.sr.ht

fbbb5f5b9e6b7552d2545ead0e81b5f602e2bba1 — Drew DeVault 1 year, 11 months ago d99ec21
Insert helpful commit message here
6 files changed, 117 insertions(+), 44 deletions(-)

D names/blueprints/names.py
M names/blueprints/web.py
A names/pygments.py
A names/templates/create.html
M names/templates/dashboard.html
A names/types/domain.py
D names/blueprints/names.py => names/blueprints/names.py +0 -3
@@ 1,3 0,0 @@
from flask import Blueprint

names = Blueprint("names.names", __name__)

M names/blueprints/web.py => names/blueprints/web.py +26 -40
@@ 1,13 1,18 @@
from flask import Blueprint, render_template
import re
from flask import Blueprint, render_template, request
from flask_login import current_user
from jinja2 import Markup
from names.pygments import ZoneLexer
from pygments import highlight
from pygments.formatters import HtmlFormatter
from pygments.lexer import RegexLexer, bygroups, include
from pygments.token import *
from srht.flask import loginrequired
from srht.validation import Validation

web = Blueprint("names.web", __name__)

# https://stackoverflow.com/a/26987741
name_re = re.compile(r'^(([a-zA-Z]{1})|([a-zA-Z]{1}[a-zA-Z]{1})|([a-zA-Z]{1}[0-9]{1})|([0-9]{1}[a-zA-Z]{1})|([a-zA-Z0-9][a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]))\.([a-zA-Z]{2,6}|[a-zA-Z0-9-]{2,30}\.[a-zA-Z]{2,3})$')

@web.route("/")
def index():
    if current_user:


@@ 15,44 20,25 @@ def index():
    else:
        return render_template("index.html")

class ZoneLexer(RegexLexer):
    name = 'Zone'
    aliases = ['zone']
    filenames = ['*.zone']
@web.route("/create")
@loginrequired
def create_GET():
    # TODO: Redirect to user contact info
    return render_template("create.html")

@web.route("/create", methods=["POST"])
@loginrequired
def create_POST():
    valid = Validation(request)
    domain = valid.require("domain_name", friendly_name="Domain name")
    valid.expect(not domain or name_re.match(domain),
            "This must be a valid RFC-1034 (+errata) domain name. " +
            "For IDNs, use punycode.", field="domain_name")
    if not valid.ok:
        return render_template("create.html", **valid.kwargs), 400

    tokens = {
        'root': [
            (r';.*\n', Comment.Single),
            (r'(\$[A-Za-z]+ )(.*\n)',
                bygroups(Comment.PreProc, Name.String)),
            (r'''(?x)
                ([A-Za-z@_][A-Za-z0-9_.-]*[\t ]+|[\t ]+)
                (IN[\t ]+)
                ((AAAA|A|NS|MX|CNAME|SOA|PTR|TXT)[\t ]+)''',
                bygroups(Name.Entity, Keyword.Reserved, Keyword.Type),
                'simple'),
            (r'.*\n', Text),
        ],
        'value': [
            (r'\(', Text, 'parenthesized'),
            (r'\d.\d.\d.\d[\t ]*', Literal.Number),
            (r'([\dA-Fa-f]+(:|::))([\dA-Fa-f]+(:|::)?]*)[\t ]*', Literal.Number),
            (r'[a-zA-Z][a-zA-Z0-9_.-]+[\t ]*', Name.Entity),
            (r'"[^\n]*"', Literal.String),
            (r'\d+(d|w|h|y)', Literal.Date),
            (r'\d+', Literal.Number),
            (r'.', Text),
        ],
        'simple': [
            (r'\n', Text, '#pop'),
            include('value'),
        ],
        'parenthesized': [
            (r'\)', Text, '#pop'),
            (r'\n', Text),
            include('value'),
        ],
    }
    # TODO: Check if user has payment info on file
    # TODO: Check if domain is available

@web.route("/mockup")
def mockup():

A names/pygments.py => names/pygments.py +41 -0
@@ 0,0 1,41 @@
from pygments.lexer import RegexLexer, bygroups, include
from pygments.token import *

class ZoneLexer(RegexLexer):
    name = 'Zone'
    aliases = ['zone']
    filenames = ['*.zone']

    tokens = {
        'root': [
            (r';.*\n', Comment.Single),
            (r'(\$[A-Za-z]+ )(.*\n)',
                bygroups(Comment.PreProc, Name.String)),
            (r'''(?x)
                ([A-Za-z@_][A-Za-z0-9_.-]*[\t ]+|[\t ]+)
                (IN[\t ]+)
                ((AAAA|A|NS|MX|CNAME|SOA|PTR|TXT)[\t ]+)''',
                bygroups(Name.Entity, Keyword.Reserved, Keyword.Type),
                'simple'),
            (r'.*\n', Text),
        ],
        'value': [
            (r'\(', Text, 'parenthesized'),
            (r'\d.\d.\d.\d[\t ]*', Literal.Number),
            (r'([\dA-Fa-f]+(:|::))([\dA-Fa-f]+(:|::)?]*)[\t ]*', Literal.Number),
            (r'[a-zA-Z][a-zA-Z0-9_.-]+[\t ]*', Name.Entity),
            (r'"[^\n]*"', Literal.String),
            (r'\d+(d|w|h|y)', Literal.Date),
            (r'\d+', Literal.Number),
            (r'.', Text),
        ],
        'simple': [
            (r'\n', Text, '#pop'),
            include('value'),
        ],
        'parenthesized': [
            (r'\)', Text, '#pop'),
            (r'\n', Text),
            include('value'),
        ],
    }

A names/templates/create.html => names/templates/create.html +24 -0
@@ 0,0 1,24 @@
{% extends "layout.html" %}
{% block content %}
<div class="row">
  <form class="col-md-6" method="POST">
    <h3>Add a new domain</h3>
    {{csrf_token()}}
    <div class="form-group">
      <label for="domain_name">Domain name</label>
      <input
        type="text"
        class="form-control {{valid.cls("domain_name")}}"
        placeholder="example.org"
        id="domain_name"
        name="domain_name"
        value="{{domain_name or ""}}" />
      {{valid.summary("domain_name")}}
    </div>
    {{valid.summary()}}
    <button class="btn btn-primary">
      Continue {{icon("caret-right")}}
    </button>
  </form>
</div>
{% endblock %}

M names/templates/dashboard.html => names/templates/dashboard.html +1 -1
@@ 8,7 8,7 @@
      service. Documentation for its use is
      <a href="https://man.sr.ht/names.sr.ht">available here</a>.
    </p>
    <a href="/create" class="btn btn-primary btn-block">
    <a href="{{url_for('.create_GET')}}" class="btn btn-primary btn-block">
      Add a domain {{icon("caret-right")}}
    </a>
  </div>

A names/types/domain.py => names/types/domain.py +25 -0
@@ 0,0 1,25 @@
import enum
import sqlalchemy as sa
import sqlalchemy_utils as sau
from srht.database import Base

class DomainStatus(enum.Enum):
    managed = 'managed'
    external = 'external'
    incoming_transfer = 'incoming_transfer'
    outgoing_transfer = 'outgoing_transfer'

class Domain(Base):
    __tablename__ = 'domain'
    id = sa.Column(sa.Integer, primary_key=True)
    created = sa.Column(sa.DateTime, nullable=False)
    updated = sa.Column(sa.DateTime, nullable=False)
    name = sa.Column(sa.String(256), nullable=False)
    status = sa.Column(sau.ChoiceType(DomainStatus, impl=sa.String),
            nullable=False, server_default='external')

    ns1 = sa.Column(sa.String)
    ns2 = sa.Column(sa.String)
    ns3 = sa.Column(sa.String)
    ns4 = sa.Column(sa.String)
    ns5 = sa.Column(sa.String)