diff --git a/app/__init__.py b/app/__init__.py index a0b4ba5..4c1512a 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -25,13 +25,15 @@ from flask_github import GitHub from flask_wtf.csrf import CsrfProtect from flask_flatpages import FlatPages from flask_babel import Babel -import os +import os, redis app = Flask(__name__, static_folder="public/static") app.config["FLATPAGES_ROOT"] = "flatpages" app.config["FLATPAGES_EXTENSION"] = ".md" app.config.from_pyfile(os.environ["FLASK_CONFIG"]) +r = redis.Redis.from_url(app.config["REDIS_URL"]) + menu.Menu(app=app) markdown = Markdown(app, extensions=["fenced_code"], safe_mode=True, output_format="html5") github = GitHub(app) diff --git a/app/blueprints/packages/releases.py b/app/blueprints/packages/releases.py index 89a9a00..60a54bd 100644 --- a/app/blueprints/packages/releases.py +++ b/app/blueprints/packages/releases.py @@ -20,6 +20,7 @@ from flask_user import * from . import bp +from app.rediscache import has_key, set_key, make_download_key from app.models import * from app.tasks.importtasks import makeVCSRelease from app.utils import * @@ -123,20 +124,18 @@ def download_release(package, id): if release is None or release.package != package: abort(404) - if release is None: - if "application/zip" in request.accept_mimetypes and \ - not "text/html" in request.accept_mimetypes: - return "", 204 - else: - flash("No download available.", "error") - return redirect(package.getDetailsURL()) - else: - PackageRelease.query.filter_by(id=release.id).update({ - "downloads": PackageRelease.downloads + 1 - }) - db.session.commit() + ip = request.headers.get("X-Forwarded-For") or request.remote_addr + if ip is not None: + key = make_download_key(ip, release.package) + if not has_key(key): + set_key(key, "true") - return redirect(release.url, code=300) + PackageRelease.query.filter_by(id=release.id).update({ + "downloads": PackageRelease.downloads + 1 + }) + db.session.commit() + + return redirect(release.url, code=300) @bp.route("/packages///releases//", methods=["GET", "POST"]) @login_required diff --git a/app/rediscache.py b/app/rediscache.py new file mode 100644 index 0000000..718a82e --- /dev/null +++ b/app/rediscache.py @@ -0,0 +1,13 @@ +from . import r + +# This file acts as a facade between the releases code and redis, +# and also means that the releases code avoids knowing about `app` + +def make_download_key(ip, package): + return ("{}/{}/{}").format(ip, package.author.username, package.name) + +def set_key(key, v): + r.set(key, v) + +def has_key(key): + return r.exists(key) diff --git a/config.example.cfg b/config.example.cfg index 09aac7f..51e3f50 100644 --- a/config.example.cfg +++ b/config.example.cfg @@ -10,8 +10,9 @@ SQLALCHEMY_DATABASE_URI = "sqlite:///../db.sqlite" GITHUB_CLIENT_ID = "" GITHUB_CLIENT_SECRET = "" -CELERY_BROKER_URL='redis://localhost:6379' -CELERY_RESULT_BACKEND='redis://localhost:6379' +REDIS_URL='redis://redis:6379' +CELERY_BROKER_URL='redis://redis:6379' +CELERY_RESULT_BACKEND='redis://redis:6379' USER_ENABLE_REGISTER = False USER_ENABLE_CHANGE_USERNAME = False diff --git a/requirements.txt b/requirements.txt index 4067ca0..fd73ebc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,7 +16,7 @@ celery==4.1.1 kombu==4.2.0 GitPython~=2.1 lxml~=4.2 -pillow~=5.3 +pillow~=6.2 pyScss~=1.3 redis==2.10.6 psycopg2~=2.7