Implement featured projects

master
Drew DeVault 2 years ago
parent 19c9a87682
commit 102fca490c
  1. 18
      hubsrht/blueprints/projects.py
  2. 11
      hubsrht/blueprints/public.py
  3. 14
      hubsrht/decorators.py
  4. 14
      hubsrht/templates/project-index.html
  5. 25
      hubsrht/templates/project-summary.html
  6. 1
      hubsrht/types/__init__.py
  7. 16
      hubsrht/types/feature.py

@ -1,7 +1,8 @@
from flask import Blueprint, render_template, request, redirect, url_for
from hubsrht.decorators import adminrequired
from hubsrht.projects import ProjectAccess, get_project
from hubsrht.services import git, hg
from hubsrht.types import Event, EventType
from hubsrht.types import Feature, Event, EventType
from hubsrht.types import Project, RepoType, Visibility
from srht.database import db
from srht.flask import paginate_query
@ -136,3 +137,18 @@ def delete_POST(owner, project_name):
db.session.delete(project)
db.session.commit()
return redirect(url_for("public.index"))
@projects.route("/<owner>/<project_name>/feature", methods=["POST"])
@adminrequired
def feature_POST(owner, project_name):
owner, project = get_project(owner, project_name, ProjectAccess.read)
valid = Validation(request)
feature = Feature()
feature.project_id = project.id
feature.summary = valid.require("summary")
if not valid.ok:
abort(400) # admin-only route, who cares
db.session.add(feature)
db.session.commit()
return redirect(url_for("public.project_index"))

@ -1,5 +1,5 @@
from flask import Blueprint, render_template, request
from hubsrht.types import Project, Event, EventType, Visibility
from hubsrht.types import Project, Feature, Event, EventType, Visibility, User
from srht.flask import paginate_query
from srht.oauth import current_user, loginrequired
from srht.search import search_by
@ -48,5 +48,12 @@ def project_index():
projects, pagination = paginate_query(projects)
features = (Feature.query
.join(Project, Feature.project_id == Project.id)
.join(User, Project.owner_id == User.id)
.filter(Project.visibility == Visibility.public)
.order_by(Feature.created.desc())
.limit(5)).all()
return render_template("project-index.html", projects=projects,
search=search, sort=sort, **pagination)
search=search, features=features, sort=sort, **pagination)

@ -0,0 +1,14 @@
from flask import redirect, abort, current_app, request
from functools import wraps
from srht.oauth import current_user, UserType
def adminrequired(f):
@wraps(f)
def wrapper(*args, **kwargs):
if not current_user:
return redirect(current_app.oauth_service.oauth_url(request.url))
elif current_user.user_type != UserType.admin:
abort(403)
else:
return f(*args, **kwargs)
return wrapper

@ -76,12 +76,16 @@
<div class="col-lg-4">
<h3>Featured projects</h3>
<div class="event-list">
{% for i in range(3) %}
<a href="#">~sircmpwn</a>/<a href="#">sourcehut</a>
{% for feature in features %}
<a href="{{url_for("users.summary_GET",
username=feature.project.owner.username)}}"
>{{feature.project.owner.canonical_name}}</a>/<a
href="{{url_for("projects.summary_GET",
owner=feature.project.owner.canonical_name,
project_name=feature.project.name)}}"
>{{feature.project.name}}</a>
<blockquote style="margin-top: 0.5rem">
SourceHut itself is a free and open-source software project. You
can read and contribute to the code, and install it on your own
servers.
{{feature.summary | md}}
</blockquote>
{% endfor %}
</div>

@ -203,5 +203,30 @@
</div>
{% endif %}
</div>
{% if current_user and current_user.user_type.value == "admin" %}
<div class="row" style="margin-top: 5rem">
<div class="col-md-6">
<h3>Feature this project</h3>
<form action="{{url_for("projects.feature_POST",
owner=project.owner.canonical_name,
project_name=project.name)}}"
method="POST">
{{csrf_token()}}
<div class="form-group">
<textarea
class="form-control"
name="summary"
rows="3"
placeholder="Featured project summary"
></textarea>
</div>
<button
type="submit"
class="btn btn-primary"
>Feature project {{icon('caret-right')}}</button>
</form>
</div>
</div>
{% endif %}
</div>
{% endblock %}

@ -11,6 +11,7 @@ class Visibility(Enum):
private = "private"
from hubsrht.types.event import Event, EventType
from hubsrht.types.feature import Feature
from hubsrht.types.mailinglist import MailingList
from hubsrht.types.project import Project
from hubsrht.types.sourcerepo import SourceRepo, RepoType

@ -0,0 +1,16 @@
import sqlalchemy as sa
import sqlalchemy_utils as sau
from hubsrht.types import Visibility
from srht.database import Base
class Feature(Base):
__tablename__ = "features"
id = sa.Column(sa.Integer, primary_key=True)
created = sa.Column(sa.DateTime, nullable=False)
project_id = sa.Column(sa.Integer,
sa.ForeignKey("project.id", ondelete="CASCADE"),
nullable=False)
project = sa.orm.relationship("Project")
summary = sa.Column(sa.Unicode(), nullable=False)
Loading…
Cancel
Save