Compare commits

..

8 Commits

Author SHA1 Message Date
rubenwardy
c9bf7a3245 Add skip button to importer 2018-12-21 14:10:46 +00:00
rubenwardy
dd368d87aa Fix various issues 2018-12-21 14:02:57 +00:00
rubenwardy
e5b279d013 Fix capitalisation in API 2018-11-25 13:21:24 +00:00
rubenwardy
8ca3437689 Revert "Add flask-admin"
This reverts commit dd6257a0a0.
2018-11-14 00:56:28 +00:00
ClobberXD
aeafb8247f Fix grammar in jumbotron 2018-11-09 10:58:39 +00:00
rubenwardy
75bab28d82 Add celery beat for topic import 2018-10-09 21:49:26 +01:00
rubenwardy
328d05bdf6 Add option to hide non-free packages in API 2018-10-03 17:06:16 +01:00
rubenwardy
2229b32c90 Add SimpleMDE to edit markdown 2018-09-14 23:10:30 +01:00
16 changed files with 92 additions and 53 deletions

1
.gitignore vendored
View File

@@ -7,6 +7,7 @@ log.txt
*.rdb *.rdb
uploads uploads
thumbnails thumbnails
celerybeat-schedule
# Created by https://www.gitignore.io/api/linux,macos,python,windows # Created by https://www.gitignore.io/api/linux,macos,python,windows

View File

@@ -393,7 +393,7 @@ class Package(db.Model):
"name": self.name, "name": self.name,
"title": self.title, "title": self.title,
"author": self.author.display_name, "author": self.author.display_name,
"shortDesc": self.shortDesc, "short_description": self.shortDesc,
"type": self.type.toName(), "type": self.type.toName(),
"release": self.getDownloadRelease().id if self.getDownloadRelease() is not None else None, "release": self.getDownloadRelease().id if self.getDownloadRelease() is not None else None,
"thumbnail": (base_url + tnurl) if tnurl is not None else None, "thumbnail": (base_url + tnurl) if tnurl is not None else None,
@@ -406,17 +406,17 @@ class Package(db.Model):
"author": self.author.display_name, "author": self.author.display_name,
"name": self.name, "name": self.name,
"title": self.title, "title": self.title,
"shortDesc": self.shortDesc, "short_description": self.shortDesc,
"desc": self.desc, "desc": self.desc,
"type": self.type.toName(), "type": self.type.toName(),
"createdAt": self.created_at, "created_at": self.created_at,
"license": self.license.name, "license": self.license.name,
"mediaLicense": self.media_license.name, "media_license": self.media_license.name,
"repo": self.repo, "repo": self.repo,
"website": self.website, "website": self.website,
"issueTracker": self.issueTracker, "issue_tracker": self.issueTracker,
"forums": self.forums, "forums": self.forums,
"provides": [x.name for x in self.provides], "provides": [x.name for x in self.provides],

View File

@@ -11,6 +11,8 @@ $(function() {
$(".pkg_meta").hide() $(".pkg_meta").hide()
$(".pkg_wiz_1").show() $(".pkg_wiz_1").show()
$("#pkg_wiz_1_skip").click(finish)
$("#pkg_wiz_1_next").click(function() { $("#pkg_wiz_1_next").click(function() {
const repoURL = $("#repo").val(); const repoURL = $("#repo").val();
if (repoURL.trim() != "") { if (repoURL.trim() != "") {

4
app/public/static/simplemde.min.css vendored Normal file

File diff suppressed because one or more lines are too long

15
app/public/static/simplemde.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -459,3 +459,15 @@ table.fancyTable tfoot td {
.wiptopic a { .wiptopic a {
color: #7ac; color: #7ac;
} }
.editor-toolbar {
background-color: #333 !important;
}
.CodeMirror {
background-color: #222 !important;
}
.editor-preview-side {
background-color: #222 !important;
}

View File

@@ -18,6 +18,7 @@
import flask import flask
from flask.ext.sqlalchemy import SQLAlchemy from flask.ext.sqlalchemy import SQLAlchemy
from celery import Celery from celery import Celery
from celery.schedules import crontab
from app import app from app import app
from app.models import * from app.models import *
@@ -64,4 +65,12 @@ def make_celery(app):
celery = make_celery(app) celery = make_celery(app)
CELERYBEAT_SCHEDULE = {
'topic_list_import': {
'task': 'app.tasks.forumtasks.importTopicList',
'schedule': crontab(minute=1, hour=1),
}
}
celery.conf.beat_schedule = CELERYBEAT_SCHEDULE
from . import importtasks, forumtasks, emails from . import importtasks, forumtasks, emails

View File

@@ -74,7 +74,7 @@ def parseTitle(title):
def getLinksFromModSearch(): def getLinksFromModSearch():
links = {} links = {}
contents = urllib.request.urlopen("http://krock-works.16mb.com/MTstuff/modList.php").read().decode("utf-8") contents = urllib.request.urlopen("https://krock-works.uk.to/minetest/modList.php").read().decode("utf-8")
for x in json.loads(contents): for x in json.loads(contents):
link = x.get("link") link = x.get("link")
if link is not None: if link is not None:
@@ -127,15 +127,18 @@ def importTopicList():
link = links_by_id.get(id) link = links_by_id.get(id)
# Fill row # Fill row
topic.topic_id = id topic.topic_id = int(id)
topic.author = user topic.author = user
topic.type = info["type"] topic.type = info["type"]
topic.title = title topic.title = title
topic.name = name topic.name = name
topic.link = link topic.link = link
topic.wip = info["wip"] topic.wip = info["wip"]
topic.posts = info["posts"] topic.posts = int(info["posts"])
topic.views = info["views"] topic.views = int(info["views"])
topic.created_at = info["date"] topic.created_at = info["date"]
for p in Package.query.all():
p.recalcScore()
db.session.commit() db.session.commit()

View File

@@ -66,7 +66,7 @@ def getKrockList():
global krock_list_cache_by_name global krock_list_cache_by_name
if krock_list_cache is None: if krock_list_cache is None:
contents = urllib.request.urlopen("http://krock-works.16mb.com/MTstuff/modList.php").read().decode("utf-8") contents = urllib.request.urlopen("https://krock-works.uk.to/minetest/modList.php").read().decode("utf-8")
list = json.loads(contents) list = json.loads(contents)
def h(x): def h(x):
@@ -149,7 +149,8 @@ class PackageTreeNode:
type = PackageType.GAME type = PackageType.GAME
elif os.path.isfile(baseDir + "/init.lua"): elif os.path.isfile(baseDir + "/init.lua"):
type = PackageType.MOD type = PackageType.MOD
elif os.path.isfile(baseDir + "/modpack.txt"): elif os.path.isfile(baseDir + "/modpack.txt") or \
os.path.isfile(baseDir + "/modpack.conf"):
type = PackageType.MOD type = PackageType.MOD
is_modpack = True is_modpack = True
elif os.path.isdir(baseDir + "/mods"): elif os.path.isdir(baseDir + "/mods"):

View File

@@ -1,12 +1,11 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block title %} {% block title %}
Admin Admin Tools
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<ul> <ul>
<li><a href="db/">Database</a></li>
<li><a href="{{ url_for('user_list_page') }}">User list</a></li> <li><a href="{{ url_for('user_list_page') }}">User list</a></li>
<li><a href="{{ url_for('tag_list_page') }}">Tag Editor</a></li> <li><a href="{{ url_for('tag_list_page') }}">Tag Editor</a></li>
<li><a href="{{ url_for('license_list_page') }}">License Editor</a></li> <li><a href="{{ url_for('license_list_page') }}">License Editor</a></li>

View File

@@ -12,8 +12,8 @@ Welcome
<p> <p>
Minetest's official content repository. Minetest's official content repository.
Browse {{ count }} packages, Browse {{ count }} packages,
majority of which available under a free and open source the majority of which are available under a free
license. and open source license.
</p> </p>
<form method="get" action="/packages/"> <form method="get" action="/packages/">

View File

@@ -51,13 +51,14 @@
<p>Enter the repo URL for the package. <p>Enter the repo URL for the package.
If the repo uses git then the metadata will be automatically imported.</p> If the repo uses git then the metadata will be automatically imported.</p>
<p>Leave blank if you don't have a repo.</p> <p>Leave blank if you don't have a repo. Click skip if the import fails.</p>
</div> </div>
{{ render_field(form.repo, class_="pkg_repo") }} {{ render_field(form.repo, class_="pkg_repo") }}
<div class="pkg_wiz_1"> <div class="pkg_wiz_1">
<a id="pkg_wiz_1_next" class="button button-primary">Next</a> <a id="pkg_wiz_1_next" class="button button-primary">Next (Autoimport)</a>
<a id="pkg_wiz_1_skip" class="button button-default">Skip Autoimport</a>
</div> </div>
<div class="pkg_wiz_2"> <div class="pkg_wiz_2">
@@ -70,6 +71,12 @@
<div class="pkg_meta">{{ render_submit_field(form.submit) }}</div> <div class="pkg_meta">{{ render_submit_field(form.submit) }}</div>
</form> </form>
<script src="/static/simplemde.min.js"></script>
<link rel="stylesheet" type="text/css" href="/static/simplemde.min.css">
<script>
var simplemde = new SimpleMDE({ element: $("#desc")[0] });
</script>
{% if enable_wizard %} {% if enable_wizard %}
<script src="/static/url.min.js"></script> <script src="/static/url.min.js"></script>
<script src="/static/polltask.js"></script> <script src="/static/polltask.js"></script>

View File

@@ -170,3 +170,13 @@ def clearNotifications(url):
if current_user.is_authenticated: if current_user.is_authenticated:
Notification.query.filter_by(user=current_user, url=url).delete() Notification.query.filter_by(user=current_user, url=url).delete()
db.session.commit() db.session.commit()
YESES = ["yes", "true", "1", "on"]
def isYes(val):
return val and val.lower() in YESES
def isNo(val):
return val and not isYes(val)

View File

@@ -27,37 +27,6 @@ from flask_wtf import FlaskForm
from wtforms import * from wtforms import *
from app.utils import loginUser, rank_required, triggerNotif from app.utils import loginUser, rank_required, triggerNotif
import datetime import datetime
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView
class MyModelView(ModelView):
def is_accessible(self):
return current_user.is_authenticated and current_user.rank.atLeast(UserRank.ADMIN)
def inaccessible_callback(self, name, **kwargs):
# redirect to login page if user doesn't have access
if current_user.is_authenticated:
abort(403)
else:
return redirect(url_for('user.login', next=request.url))
admin = Admin(app, name='ContentDB', template_mode='bootstrap3', url="/admin/db")
admin.add_view(MyModelView(User, db.session))
admin.add_view(MyModelView(Package, db.session))
admin.add_view(MyModelView(Dependency, db.session))
admin.add_view(MyModelView(EditRequest, db.session))
admin.add_view(MyModelView(EditRequestChange, db.session))
admin.add_view(MyModelView(ForumTopic, db.session))
admin.add_view(MyModelView(License, db.session))
admin.add_view(MyModelView(MetaPackage, db.session))
admin.add_view(MyModelView(Notification, db.session))
admin.add_view(MyModelView(PackageRelease, db.session))
admin.add_view(MyModelView(PackageScreenshot, db.session))
admin.add_view(MyModelView(Tag, db.session))
admin.add_view(MyModelView(Thread, db.session))
admin.add_view(MyModelView(ThreadReply, db.session))
admin.add_view(MyModelView(UserEmailVerification, db.session))
@app.route("/admin/", methods=["GET", "POST"]) @app.route("/admin/", methods=["GET", "POST"])
@rank_required(UserRank.ADMIN) @rank_required(UserRank.ADMIN)
@@ -110,8 +79,8 @@ def admin_page():
rel = PackageRelease() rel = PackageRelease()
rel.package = package rel.package = package
rel.title = datetime.date.today().isoformat() rel.title = datetime.date.today().isoformat()
rel.url = "" rel.url = ""
rel.task_id = uuid() rel.task_id = uuid()
rel.approved = True rel.approved = True
db.session.add(rel) db.session.add(rel)
@@ -129,7 +98,6 @@ def admin_page():
deleted_packages = Package.query.filter_by(soft_deleted=True).all() deleted_packages = Package.query.filter_by(soft_deleted=True).all()
return render_template("admin/list.html", deleted_packages=deleted_packages) return render_template("admin/list.html", deleted_packages=deleted_packages)
class SwitchUserForm(FlaskForm): class SwitchUserForm(FlaskForm):
username = StringField("Username") username = StringField("Username")
submit = SubmitField("Switch") submit = SubmitField("Switch")

View File

@@ -51,6 +51,7 @@ class QueryBuilder:
self.types = types self.types = types
self.search = request.args.get("q") self.search = request.args.get("q")
self.lucky = "lucky" in request.args self.lucky = "lucky" in request.args
self.hide_nonfree = isNo(request.args.get("nonfree"))
self.limit = 1 if self.lucky else None self.limit = 1 if self.lucky else None
def buildPackageQuery(self): def buildPackageQuery(self):
@@ -64,6 +65,10 @@ class QueryBuilder:
query = query.order_by(db.desc(Package.score)) query = query.order_by(db.desc(Package.score))
if self.hide_nonfree:
query = query.filter(Package.license.has(License.is_foss == True))
query = query.filter(Package.media_license.has(License.is_foss == True))
if self.limit: if self.limit:
query = query.limit(self.limit) query = query.limit(self.limit)
@@ -78,6 +83,10 @@ class QueryBuilder:
if len(self.types) > 0: if len(self.types) > 0:
topics = topics.filter(ForumTopic.type.in_(self.types)) topics = topics.filter(ForumTopic.type.in_(self.types))
if self.hide_nonfree:
query = query.filter(Package.license.has(License.is_foss == True))
query = query.filter(Package.media_license.has(License.is_foss == True))
if self.limit: if self.limit:
topics = topics.limit(self.limit) topics = topics.limit(self.limit)

View File

@@ -6,7 +6,7 @@ Flask-Menu>=0.7.0
Flask-Markdown>=0.3 Flask-Markdown>=0.3
GitHub-Flask>=3.2.0 GitHub-Flask>=3.2.0
pyScss==1.3.4 pyScss==1.3.4
celery==4.0.2 celery==4.1.1
redis==2.10.6 redis==2.10.6
beautifulsoup4==4.6.0 beautifulsoup4==4.6.0
lxml==4.2.1 lxml==4.2.1
@@ -14,4 +14,3 @@ Flask-FlatPages==0.6
Flask-Migrate==2.1.1 Flask-Migrate==2.1.1
pillow==5.1.0 pillow==5.1.0
GitPython==2.1.10 GitPython==2.1.10
flask-admin==1.5.1