Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c9bf7a3245 | ||
|
|
dd368d87aa | ||
|
|
e5b279d013 | ||
|
|
8ca3437689 | ||
|
|
aeafb8247f | ||
|
|
75bab28d82 | ||
|
|
328d05bdf6 | ||
|
|
2229b32c90 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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],
|
||||||
|
|||||||
@@ -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
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
15
app/public/static/simplemde.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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"):
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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/">
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
10
app/utils.py
10
app/utils.py
@@ -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)
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|||||||
Reference in New Issue
Block a user