Implement featured projects

This commit is contained in:
Drew DeVault 2020-04-28 14:08:56 -04:00
parent 19c9a87682
commit 102fca490c
7 changed files with 91 additions and 8 deletions

View File

@ -1,7 +1,8 @@
from flask import Blueprint, render_template, request, redirect, url_for from flask import Blueprint, render_template, request, redirect, url_for
from hubsrht.decorators import adminrequired
from hubsrht.projects import ProjectAccess, get_project from hubsrht.projects import ProjectAccess, get_project
from hubsrht.services import git, hg 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 hubsrht.types import Project, RepoType, Visibility
from srht.database import db from srht.database import db
from srht.flask import paginate_query from srht.flask import paginate_query
@ -136,3 +137,18 @@ def delete_POST(owner, project_name):
db.session.delete(project) db.session.delete(project)
db.session.commit() db.session.commit()
return redirect(url_for("public.index")) 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"))

View File

@ -1,5 +1,5 @@
from flask import Blueprint, render_template, request 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.flask import paginate_query
from srht.oauth import current_user, loginrequired from srht.oauth import current_user, loginrequired
from srht.search import search_by from srht.search import search_by
@ -48,5 +48,12 @@ def project_index():
projects, pagination = paginate_query(projects) 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, return render_template("project-index.html", projects=projects,
search=search, sort=sort, **pagination) search=search, features=features, sort=sort, **pagination)

14
hubsrht/decorators.py Normal file
View File

@ -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

View File

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

View File

@ -203,5 +203,30 @@
</div> </div>
{% endif %} {% endif %}
</div> </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> </div>
{% endblock %} {% endblock %}

View File

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

16
hubsrht/types/feature.py Normal file
View File

@ -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)