From 7ba6e53d92ecc5a3ac56a2c035a232189d019573 Mon Sep 17 00:00:00 2001 From: Rebecca Date: Thu, 3 Oct 2019 19:57:07 -0400 Subject: [PATCH 01/12] Added mp3 support --- gallery/file_modules/__init__.py | 4 +++- gallery/file_modules/mp3.py | 12 ++++++++++++ gallery/templates/view_file.html | 6 ++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 gallery/file_modules/mp3.py diff --git a/gallery/file_modules/__init__.py b/gallery/file_modules/__init__.py index 3ac7f11..46ff754 100644 --- a/gallery/file_modules/__init__.py +++ b/gallery/file_modules/__init__.py @@ -62,6 +62,7 @@ def generate_thumbnail(self): from gallery.file_modules.ogg import OggFile from gallery.file_modules.pdf import PDFFile from gallery.file_modules.txt import TXTFile +from gallery.file_modules.mp3 import MP3File file_mimetype_relation = { "image/jpeg": JPEGFile, @@ -77,7 +78,8 @@ def generate_thumbnail(self): "video/webm": WebMFile, "video/ogg": OggFile, "application/pdf": PDFFile, - "text/plain": TXTFile + "text/plain": TXTFile, + "audio/mpeg": MP3File } diff --git a/gallery/file_modules/mp3.py b/gallery/file_modules/mp3.py new file mode 100644 index 0000000..bb4a2d9 --- /dev/null +++ b/gallery/file_modules/mp3.py @@ -0,0 +1,12 @@ +from gallery.file_modules import FileModule +from gallery.util import DEFAULT_THUMBNAIL_NAME + +class MP3File(FileModule): + def __init__(self, file_path, dir_path): + FileModule.__init__(self, file_path, dir_path) + self.mime_type = "audio/mpeg" + + self.generate_thumbnail() + + def generate_thumbnail(self): + self.thumbnail_uuid = DEFAULT_THUMBNAIL_NAME + ".jpg" diff --git a/gallery/templates/view_file.html b/gallery/templates/view_file.html index 0864e77..828a794 100644 --- a/gallery/templates/view_file.html +++ b/gallery/templates/view_file.html @@ -64,6 +64,12 @@ {% elif file.mimetype == "application/pdf" or file.mimetype == "text/plain" %} + + {% elif file.mimetype.split('/')[0] == "audio" %} + + {% else %} Text Data {% endif %} From 769caff95a1b42e98626db62521a79a918fbcae5 Mon Sep 17 00:00:00 2001 From: Rebecca Date: Thu, 3 Oct 2019 20:58:27 -0400 Subject: [PATCH 02/12] Added wav support, added default thumbnail --- gallery/file_modules/__init__.py | 4 +++- gallery/file_modules/mp3.py | 12 +++++++++--- gallery/file_modules/wav.py | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 gallery/file_modules/wav.py diff --git a/gallery/file_modules/__init__.py b/gallery/file_modules/__init__.py index 46ff754..39917ab 100644 --- a/gallery/file_modules/__init__.py +++ b/gallery/file_modules/__init__.py @@ -63,6 +63,7 @@ def generate_thumbnail(self): from gallery.file_modules.pdf import PDFFile from gallery.file_modules.txt import TXTFile from gallery.file_modules.mp3 import MP3File +from gallery.file_modules.wav import WAVFile file_mimetype_relation = { "image/jpeg": JPEGFile, @@ -79,7 +80,8 @@ def generate_thumbnail(self): "video/ogg": OggFile, "application/pdf": PDFFile, "text/plain": TXTFile, - "audio/mpeg": MP3File + "audio/mpeg": MP3File, + "audio/x-wav": WAVFile } diff --git a/gallery/file_modules/mp3.py b/gallery/file_modules/mp3.py index bb4a2d9..6fb4c9b 100644 --- a/gallery/file_modules/mp3.py +++ b/gallery/file_modules/mp3.py @@ -1,5 +1,8 @@ +import os +from wand.image import Image + from gallery.file_modules import FileModule -from gallery.util import DEFAULT_THUMBNAIL_NAME +from gallery.util import hash_file class MP3File(FileModule): def __init__(self, file_path, dir_path): @@ -7,6 +10,9 @@ def __init__(self, file_path, dir_path): self.mime_type = "audio/mpeg" self.generate_thumbnail() - + def generate_thumbnail(self): - self.thumbnail_uuid = DEFAULT_THUMBNAIL_NAME + ".jpg" + self.thumbnail_uuid = hash_file(self.file_path) + ".jpg" + + with Image(filename="thumbnails/reedphoto.jpg") as bg: + bg.save(filename=os.path.join(self.dir_path, self.thumbnail_uuid)) diff --git a/gallery/file_modules/wav.py b/gallery/file_modules/wav.py new file mode 100644 index 0000000..71d251f --- /dev/null +++ b/gallery/file_modules/wav.py @@ -0,0 +1,18 @@ +import os +from wand.image import Image + +from gallery.file_modules import FileModule +from gallery.util import hash_file + +class WAVFile(FileModule): + def __init__(self, file_path, dir_path): + FileModule.__init__(self, file_path, dir_path) + self.mime_type = "audio/x-wav" + + self.generate_thumbnail() + + def generate_thumbnail(self): + self.thumbnail_uuid = hash_file(self.file_path) + ".jpg" + + with Image(filename="thumbnails/reedphoto.jpg") as bg: + bg.save(filename=os.path.join(self.dir_path, self.thumbnail_uuid)) From 26662f41cd465d3728c367f1d1e4e6909d85d760 Mon Sep 17 00:00:00 2001 From: Owen Miller <31546566+owencmiller@users.noreply.github.com> Date: Tue, 8 Oct 2019 16:01:38 -0400 Subject: [PATCH 03/12] Remove hidden files from directory thumbnails (#56) * Remove hidden file from directory thumbnails * Fix typo * Fix show button * Update README with local dev instructions * Fix directory thumbnails showing hidden files --- README.md | 11 +++++++ gallery/__init__.py | 57 +++++++++++++++++++++++------------- gallery/static/js/gallery.js | 2 +- localconfig.env.py | 29 ++++++++++++++++++ requirements.txt | 2 +- 5 files changed, 78 insertions(+), 23 deletions(-) create mode 100644 localconfig.env.py diff --git a/README.md b/README.md index 324ed05..0a56802 100644 --- a/README.md +++ b/README.md @@ -65,3 +65,14 @@ an Openshift Origin cluster. GALLERY_S3_BUCKET_ID = $s3BucketID GALLERY_S3_SECRET_KEY = $s3SecretKey ``` + +## Local Development +Below are instructions for running gallery locally. It assumes that you have already forked and cloned this repository onto your local machine. + +1. Change the line in `__init__.py` that sets the config file from `config.env.py` to `localconfig.env.py`. + +2. Get gallery dev secrets from an RTP and fill in `localconfig.env.py`. *DO NOT COMMIT THESE TO GIT* + +3. Run `pip install -r requirements.txt` + +4. Run `python3 wsgi.py` \ No newline at end of file diff --git a/gallery/__init__.py b/gallery/__init__.py index 8ea5fcc..18b737a 100644 --- a/gallery/__init__.py +++ b/gallery/__init__.py @@ -25,6 +25,7 @@ from flask import send_from_directory from flask import abort from flask_sqlalchemy import SQLAlchemy +from sqlalchemy import or_ from sqlalchemy.sql import func as sql_func from sqlalchemy.orm import load_only from flask_pyoidc.flask_pyoidc import OIDCAuthentication @@ -213,7 +214,7 @@ def upload_file(auth_dict: Optional[Dict[str, Any]] = None): upload_status['error'] = errors upload_status['success'] = success - refresh_thumbnail() + refresh_default_thumbnails() # actually redirect to URL # change from FORM post to AJAX maybe? return jsonify(upload_status) @@ -311,7 +312,7 @@ def api_mkdir( @app.cli.command() def refresh_thumbnails(): click.echo("Refreshing thumbnails") - refresh_thumbnail() + refresh_default_thumbnails() @app.cli.command() @@ -386,24 +387,25 @@ def add_file(file_name: str, path: str, dir_id: str, description: str, owner: st return file_model -def refresh_thumbnail(): - def refresh_thumbnail_helper(dir_model: Directory) -> str: - dir_children = [d for d in Directory.query.filter(Directory.parent == dir_model.id).all()] - file_children = [f for f in File.query.filter(File.parent == dir_model.id).all()] - for file in file_children: - if file.thumbnail_uuid != DEFAULT_THUMBNAIL_NAME: - return file.thumbnail_uuid - for d in dir_children: - if d.thumbnail_uuid != DEFAULT_THUMBNAIL_NAME: - return d.thumbnail_uuid - # WE HAVE TO GO DEEPER (inception noise) - for d in dir_children: - # TODO: Switch to iterative tree walk using a queue to avoid - # recursion issues with super large directory structures - return refresh_thumbnail_helper(d) - # No thumbnail found - return DEFAULT_THUMBNAIL_NAME - +def refresh_directory_thumbnail(dir_model: Directory) -> str: + dir_children = [d for d in Directory.query.filter(Directory.parent == dir_model.id).all()] + file_children = [f for f in File.query.filter(File.parent == dir_model.id).all()] + for file in file_children: + if file.thumbnail_uuid != DEFAULT_THUMBNAIL_NAME and not file.hidden: + return file.thumbnail_uuid + for d in dir_children: + if d.thumbnail_uuid != DEFAULT_THUMBNAIL_NAME: + return d.thumbnail_uuid + # WE HAVE TO GO DEEPER (inception noise) + for d in dir_children: + # TODO: Switch to iterative tree walk using a queue to avoid + # recursion issues with super large directory structures + return refresh_directory_thumbnail(d) + # No thumbnail found + return DEFAULT_THUMBNAIL_NAME + + +def refresh_default_thumbnails(): missing_thumbnails = File.query.filter(File.thumbnail_uuid == DEFAULT_THUMBNAIL_NAME).all() for file_model in missing_thumbnails: dir_path = get_full_dir_path(file_model.parent) @@ -416,7 +418,7 @@ def refresh_thumbnail_helper(dir_model: Directory) -> str: missing_thumbnails = Directory.query.filter(Directory.thumbnail_uuid == DEFAULT_THUMBNAIL_NAME).all() for dir_model in missing_thumbnails: - dir_model.thumbnail_uuid = refresh_thumbnail_helper(dir_model) + dir_model.thumbnail_uuid = refresh_directory_thumbnail(dir_model) db.session.flush() db.session.commit() db.session.refresh(dir_model) @@ -476,6 +478,13 @@ def hide_file(file_id: int, auth_dict: Optional[Dict[str, Any]] = None): return "Permission denied", 403 file_model.hidden = True + + # Remove image from thumbnails + dirs = Directory.query.filter(or_(Directory.thumbnail_uuid == file_model.thumbnail_uuid, \ + Directory.thumbnail_uuid == file_model.thumbnail_uuid[:-4])) + for d in dirs: + d.thumbnail_uuid = refresh_directory_thumbnail(d) + db.session.flush() db.session.commit() @@ -497,6 +506,12 @@ def show_file(file_id: int, auth_dict: Optional[Dict[str, Any]] = None): return "Permission denied", 403 file_model.hidden = False + + # Add image as directory thumbnail + parent_model = Directory.query.filter(Directory.id == file_model.parent).first() + if parent_model.thumbnail_uuid == DEFAULT_THUMBNAIL_NAME: + parent_model.thumbnail_uuid = refresh_directory_thumbnail(parent_model) + db.session.flush() db.session.commit() diff --git a/gallery/static/js/gallery.js b/gallery/static/js/gallery.js index b4b44a4..9bcbb79 100644 --- a/gallery/static/js/gallery.js +++ b/gallery/static/js/gallery.js @@ -252,7 +252,7 @@ function hideFile() { function showFile() { $('#show').modal('show'); - $('#show button[id^="hide"]').click(function(e) { + $('#show button[id^="show"]').click(function(e) { e.preventDefault(); var this_id = $('#show button[id^="show"]').attr('id').substr($('#show button[id^="show"]').attr('id').indexOf("-") + 1); $.ajax({ diff --git a/localconfig.env.py b/localconfig.env.py new file mode 100644 index 0000000..8cf7bfc --- /dev/null +++ b/localconfig.env.py @@ -0,0 +1,29 @@ +import os + +# Flask config +DEBUG=False +IP=os.environ.get('GALLERY_IP', 'localhost') +PORT=os.environ.get('GALLERY_PORT', '6969') +SERVER_NAME = os.environ.get('GALLERY_SERVER_NAME', 'localhost:6969') +SECRET_KEY = os.environ.get('GALLERY_SECRET_KEY', '') + +# LDAP config +LDAP_URL=os.environ.get('GALLERY_LDAP_URL', 'ldaps://ldap.csh.rit.edu:636') +LDAP_BIND_DN=os.environ.get('GALLERY_LDAP_BIND_DN', '') +LDAP_BIND_PW=os.environ.get('GALLERY_LDAP_BIND_PW', '') +LDAP_USER_OU=os.environ.get('GALLERY_LDAP_USER_OU', 'ou=Users,dc=csh,dc=rit,dc=edu') + +# OpenID Connect SSO config +OIDC_ISSUER = os.environ.get('GALLERY_OIDC_ISSUER', 'https://sso.csh.rit.edu/auth/realms/csh') +OIDC_CLIENT_ID = os.environ.get('GALLERY_OIDC_CLIENT_ID', 'gallery-dev') +OIDC_CLIENT_SECRET = os.environ.get('GALLERY_OIDC_CLIENT_SECRET', '') + +SQLALCHEMY_DATABASE_URI = os.environ.get( + 'GALLERY_DATABASE_URI', + 'postgresql://gallery:undergrowth7803824=exhibitionist@postgres.csh.rit.edu/gallery-dev') +SQLALCHEMY_TRACK_MODIFICATIONS = False + +S3_URI = os.environ.get('GALLERY_S3_URI', 'https://s3.csh.rit.edu') +S3_ACCESS_ID = os.environ.get('GALLERY_S3_ACCESS_ID','') +S3_SECRET_KEY = os.environ.get('GALLERY_S3_SECRET_KEY','') +S3_BUCKET_ID = os.environ.get('GALLERY_S3_BUCKET_ID','gallery-dev') diff --git a/requirements.txt b/requirements.txt index de06ac5..aae44a7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ Flask==1.0.2 Flask-pyoidc==2.0.0 -csh_ldap==2.1.1 +csh_ldap~=2.2.0 addict==2.2.0 flask_sqlalchemy==2.3.2 flask_migrate==2.3.1 From 00d1aa7405931c674ad97dbf8254874a561d7690 Mon Sep 17 00:00:00 2001 From: Ram Zallan Date: Wed, 9 Oct 2019 15:38:42 -0400 Subject: [PATCH 04/12] Various lockdown fixes (#58) * Add .swp files to gitignore * Display more helpful lockdown page, move more routes behind lockdown --- .gitignore | 3 ++ gallery/__init__.py | 46 +++++++++++++++++++++---- gallery/static/images/material_lock.svg | 1 + gallery/templates/errors.html | 13 ++++--- 4 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 gallery/static/images/material_lock.svg diff --git a/.gitignore b/.gitignore index 33a5696..b524b30 100644 --- a/.gitignore +++ b/.gitignore @@ -97,3 +97,6 @@ data.db # mypy .mypy_cache + +# vim swap files +*.swp diff --git a/gallery/__init__.py b/gallery/__init__.py index 18b737a..2fc5925 100644 --- a/gallery/__init__.py +++ b/gallery/__init__.py @@ -247,6 +247,9 @@ def view_mkdir(auth_dict: Optional[Dict[str, Any]] = None): @auth.oidc_auth('default') @gallery_auth def view_jumpdir(auth_dict: Optional[Dict[str, Any]] = None): + gallery_lockdown = util.get_lockdown_status() + if gallery_lockdown and (not auth_dict['is_eboard'] and not auth_dict['is_rtp']): + abort(405) return render_template("jumpdir.html", auth_dict=auth_dict) @@ -733,7 +736,12 @@ def tag_file(file_id: int): @app.route("/api/file/get/") @auth.oidc_auth('default') -def display_file(file_id: int): +@gallery_auth +def display_file(file_id: int, auth_dict: Optional[Dict[str, Any]] = None): + gallery_lockdown = util.get_lockdown_status() + if gallery_lockdown and (not auth_dict['is_eboard'] and not auth_dict['is_rtp']): + abort(405) + file_model = File.query.filter(File.id == file_id).first() if file_model is None: @@ -745,7 +753,12 @@ def display_file(file_id: int): @app.route("/api/thumbnail/get/") @auth.oidc_auth('default') -def display_thumbnail(file_id: int): +@gallery_auth +def display_thumbnail(file_id: int, auth_dict: Optional[Dict[str, Any]] = None): + gallery_lockdown = util.get_lockdown_status() + if gallery_lockdown and (not auth_dict['is_eboard'] and not auth_dict['is_rtp']): + abort(405) + file_model = File.query.filter(File.id == file_id).first() link = storage_interface.get_link("thumbnails/{}".format(file_model.s3_id)) @@ -754,7 +767,12 @@ def display_thumbnail(file_id: int): @app.route("/api/thumbnail/get/dir/") @auth.oidc_auth('default') -def display_dir_thumbnail(dir_id: int): +@gallery_auth +def display_dir_thumbnail(dir_id: int, auth_dict: Optional[Dict[str, Any]] = None): + gallery_lockdown = util.get_lockdown_status() + if gallery_lockdown and (not auth_dict['is_eboard'] and not auth_dict['is_rtp']): + abort(405) + dir_model = Directory.query.filter(Directory.id == dir_id).first() thumbnail_uuid = dir_model.thumbnail_uuid @@ -810,7 +828,11 @@ def get_supported_mimetypes(): @app.route("/api/get_dir_tree") @auth.oidc_auth('default') -def get_dir_tree(internal: bool = False): +@gallery_auth +def get_dir_tree(internal: bool = False, auth_dict: Optional[Dict[str, Any]] = None): + gallery_lockdown = util.get_lockdown_status() + if gallery_lockdown and (not auth_dict['is_eboard'] and not auth_dict['is_rtp']): + abort(405) # TODO: Convert to iterative tree traversal using a queue to avoid # recursion issues with large directory structures @@ -843,7 +865,12 @@ def get_dir_children(dir_id: int) -> Any: @app.route("/api/directory/get/") @auth.oidc_auth('default') -def display_files(dir_id: int, internal: bool = False): +@gallery_auth +def display_files(dir_id: int, internal: bool = False, auth_dict: Optional[Dict[str, Any]] = None): + gallery_lockdown = util.get_lockdown_status() + if gallery_lockdown and (not auth_dict['is_eboard'] and not auth_dict['is_rtp']): + abort(405) + file_list = [("File", f) for f in File.query.filter(File.parent == dir_id).all()] dir_list = [("Directory", d) for d in Directory.query.filter(Directory.parent == dir_id).all()] @@ -995,7 +1022,12 @@ def view_filtered(auth_dict: Optional[Dict[str, Any]] = None): @app.route("/api/memberlist") @auth.oidc_auth('default') -def get_member_list(): +@gallery_auth +def get_member_list(auth_dict: Optional[Dict[str, Any]] = None): + gallery_lockdown = util.get_lockdown_status() + if gallery_lockdown and (not auth_dict['is_eboard'] and not auth_dict['is_rtp']): + abort(405) + return jsonify(ldap.get_members()) @@ -1014,7 +1046,7 @@ def route_errors(error: Any, auth_dict: Optional[Dict[str, Any]] = None): if code == 404: error_desc = "Page Not Found" elif code == 405: - error_desc = "Page Not Available" + error_desc = "Gallery is currently unavailable" else: error_desc = type(error).__name__ diff --git a/gallery/static/images/material_lock.svg b/gallery/static/images/material_lock.svg new file mode 100644 index 0000000..cc19cec --- /dev/null +++ b/gallery/static/images/material_lock.svg @@ -0,0 +1 @@ + diff --git a/gallery/templates/errors.html b/gallery/templates/errors.html index e5204ee..bc5a7ee 100644 --- a/gallery/templates/errors.html +++ b/gallery/templates/errors.html @@ -6,10 +6,15 @@ {% block body %}
- Attention! -

Oops!

-

Something has gone terribly wrong!

-

{{ error }}

+ {% if error_code == 405 %} + Locked +

{{ error }}

+ {% else %} + Attention +

Oops!

+

Something has gone terribly wrong!

+

{{ error }}

+ {% endif %}
{% endblock %} From aa63f2e046fa161374506dc94cbfea22c747510b Mon Sep 17 00:00:00 2001 From: Ram Zallan Date: Wed, 9 Oct 2019 15:45:04 -0400 Subject: [PATCH 05/12] Version bump --- gallery/_version.py | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gallery/_version.py b/gallery/_version.py index 125c525..f67c258 100644 --- a/gallery/_version.py +++ b/gallery/_version.py @@ -1,6 +1,6 @@ from os import environ as env -__version__ = "2.1.0" +__version__ = "2.1.1" BUILD_REFERENCE = env.get("OPENSHIFT_BUILD_REFERENCE") COMMIT_HASH = env.get("OPENSHIFT_BUILD_COMMIT") diff --git a/setup.cfg b/setup.cfg index 18f1f67..eb28da7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,7 +6,7 @@ summary = Python Photo Gallery Written in Flask url = "https://github.com/ComputerScienceHouse/gallery" description-file = README.md license = MIT -version = 2.0.5 +version = 2.1.1 classifier = Natural Language :: English Operating System :: POSIX :: Linux From 00b5ca5b7f461f1df24c3ff2bb975130cee7a29d Mon Sep 17 00:00:00 2001 From: Ram Zallan Date: Wed, 9 Oct 2019 19:39:20 -0400 Subject: [PATCH 06/12] Remove old password from localconfig --- localconfig.env.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/localconfig.env.py b/localconfig.env.py index 8cf7bfc..d3f5ef4 100644 --- a/localconfig.env.py +++ b/localconfig.env.py @@ -20,7 +20,7 @@ SQLALCHEMY_DATABASE_URI = os.environ.get( 'GALLERY_DATABASE_URI', - 'postgresql://gallery:undergrowth7803824=exhibitionist@postgres.csh.rit.edu/gallery-dev') + 'postgresql://DB_USERNAME:DB_PASSWORD@postgres.csh.rit.edu/gallery-dev') SQLALCHEMY_TRACK_MODIFICATIONS = False S3_URI = os.environ.get('GALLERY_S3_URI', 'https://s3.csh.rit.edu') From 773b30fab2bfac69e6ac7573dc4954d0192fbcf5 Mon Sep 17 00:00:00 2001 From: Ram Zallan Date: Wed, 9 Oct 2019 21:39:09 -0400 Subject: [PATCH 07/12] Update local development instructions and gitignore --- .gitignore | 2 ++ README.md | 12 ++++++++---- localconfig.env.py => localconfig-sample.env.py | 2 -- 3 files changed, 10 insertions(+), 6 deletions(-) rename localconfig.env.py => localconfig-sample.env.py (87%) diff --git a/.gitignore b/.gitignore index b524b30..ad7bae3 100644 --- a/.gitignore +++ b/.gitignore @@ -89,6 +89,8 @@ ENV/ # Rope project settings .ropeproject +# Local development files +localconfig.env.py config.py data.db diff --git a/README.md b/README.md index 0a56802..40b0bd4 100644 --- a/README.md +++ b/README.md @@ -67,12 +67,16 @@ an Openshift Origin cluster. ``` ## Local Development -Below are instructions for running gallery locally. It assumes that you have already forked and cloned this repository onto your local machine. +Below are instructions for running gallery locally. It assumes that you have already forked and cloned this repository onto your local machine, and have Python3 installed. 1. Change the line in `__init__.py` that sets the config file from `config.env.py` to `localconfig.env.py`. -2. Get gallery dev secrets from an RTP and fill in `localconfig.env.py`. *DO NOT COMMIT THESE TO GIT* +2. Copy `localconfig-sample.env.py` to `localconfig.env.py`, get gallery dev secrets from an RTP, and fill in. -3. Run `pip install -r requirements.txt` +3. Create a [virtual environment](https://docs.python.org/3/library/venv.html), `python3 -m venv venv` -4. Run `python3 wsgi.py` \ No newline at end of file +4. `source venv/bin/activate` to enter the virtual environment + +5. `pip install -r requirements.txt` + +6. `python3 wsgi.py` diff --git a/localconfig.env.py b/localconfig-sample.env.py similarity index 87% rename from localconfig.env.py rename to localconfig-sample.env.py index d3f5ef4..e61e250 100644 --- a/localconfig.env.py +++ b/localconfig-sample.env.py @@ -8,10 +8,8 @@ SECRET_KEY = os.environ.get('GALLERY_SECRET_KEY', '') # LDAP config -LDAP_URL=os.environ.get('GALLERY_LDAP_URL', 'ldaps://ldap.csh.rit.edu:636') LDAP_BIND_DN=os.environ.get('GALLERY_LDAP_BIND_DN', '') LDAP_BIND_PW=os.environ.get('GALLERY_LDAP_BIND_PW', '') -LDAP_USER_OU=os.environ.get('GALLERY_LDAP_USER_OU', 'ou=Users,dc=csh,dc=rit,dc=edu') # OpenID Connect SSO config OIDC_ISSUER = os.environ.get('GALLERY_OIDC_ISSUER', 'https://sso.csh.rit.edu/auth/realms/csh') From 2d761d620d8df6fb8a8ed80ddac95961b36bca56 Mon Sep 17 00:00:00 2001 From: Jack Sauriol Date: Wed, 18 Mar 2020 13:05:04 -0400 Subject: [PATCH 08/12] Allow alumni to view hidden files (#62) * Allow alumni to view hidden files * Update nav.html --- gallery/__init__.py | 3 +-- gallery/ldap.py | 3 +++ gallery/templates/view_dir.html | 2 +- gallery/util.py | 2 ++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/gallery/__init__.py b/gallery/__init__.py index 2fc5925..0161b6f 100644 --- a/gallery/__init__.py +++ b/gallery/__init__.py @@ -922,7 +922,6 @@ def render_dir(dir_id: int, auth_dict: Optional[Dict[str, Any]] = None): description = dir_model.description display_description = len(description) > 0 - display_parent = True if dir_model is None or dir_model.parent is None or dir_id == ROOT_DIR_ID: display_parent = False @@ -960,7 +959,7 @@ def render_file(file_id: int, auth_dict: Optional[Dict[str, Any]] = None): file_model = File.query.filter(File.id == file_id).first() if file_model is None: abort(404) - if file_model.hidden and (not auth_dict['is_eboard'] and not auth_dict['is_rtp']): + if file_model.hidden and (not auth_dict['is_eboard'] and not auth_dict['is_rtp'] and not auth_dict['is_alumni']): abort(404) gallery_lockdown = util.get_lockdown_status() if gallery_lockdown and (not auth_dict['is_eboard'] and not auth_dict['is_rtp']): diff --git a/gallery/ldap.py b/gallery/ldap.py index 4235426..0a08d66 100644 --- a/gallery/ldap.py +++ b/gallery/ldap.py @@ -41,6 +41,9 @@ def is_rtp(self, uid: str) -> bool: rtp_group = self._ldap.get_group('rtp') return rtp_group.check_member(self._ldap.get_member(uid, uid=True)) + def is_alumni(self, uid: str) -> bool: + return not is_member_of_group(self._ldap.get_member(uid, uid=True), 'current_student') + def get_members(self) -> List[Dict[str, str]]: if self._ldap is None: return [] diff --git a/gallery/templates/view_dir.html b/gallery/templates/view_dir.html index d86b054..840f687 100644 --- a/gallery/templates/view_dir.html +++ b/gallery/templates/view_dir.html @@ -35,7 +35,7 @@ {% if children|length >= 1 %}
{% for child_type, child in children %} - {% if not child.hidden or (auth_dict['is_eboard'] or auth_dict['is_rtp']) %} + {% if not child.hidden or (auth_dict['is_eboard'] or auth_dict['is_rtp']) or auth_dict['is_alumni'] %}
diff --git a/gallery/util.py b/gallery/util.py index 3051c25..6f67f20 100644 --- a/gallery/util.py +++ b/gallery/util.py @@ -74,6 +74,7 @@ def wrapped_function(*args: Any, **kwargs: Any) -> Any: name = ldap.convert_uuid_to_displayname(uuid) is_eboard = ldap.is_eboard(uid) is_rtp = ldap.is_rtp(uid) + is_alumni = ldap.is_alumni(uid) # NOTE(rossdylan): This is probably a more precise type than we need, # if different data is needed just expand the value type to Any @@ -83,6 +84,7 @@ def wrapped_function(*args: Any, **kwargs: Any) -> Any: auth_dict['name'] = name auth_dict['is_eboard'] = is_eboard auth_dict['is_rtp'] = is_rtp + auth_dict['is_alumni'] = is_alumni kwargs['auth_dict'] = auth_dict return func(*args, **kwargs) return wrapped_function From 6cd5271393b09686c4e0f2f009f9278a62fbafaa Mon Sep 17 00:00:00 2001 From: Max Meinhold Date: Thu, 19 Mar 2020 13:43:07 -0400 Subject: [PATCH 09/12] Upgrade pip to fix builds (#64) * Upgrade pip Fixes Docker build issue caused by an issue in pip 19 Issue occurred when using --no-cache-dir * Pip werkzeug version --- Dockerfile | 2 ++ requirements.txt | 1 + 2 files changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index 8ec8137..6a7786c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,6 +10,8 @@ RUN apt-get update && \ rm -rf /var/lib/{apt,dpkg,cache,log}/ && \ mkdir -p /opt/gallery /var/lib/gallery +RUN pip install --upgrade pip + WORKDIR /opt/gallery ADD . /opt/gallery diff --git a/requirements.txt b/requirements.txt index aae44a7..a74cbc9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,3 +12,4 @@ gunicorn==19.9.0 moviepy==0.2.3.5 imageio==2.4.0 boto3 +werkzeug == 0.16.1 From 103829abb8d6d564a10ff8f09834d6e84025a9a4 Mon Sep 17 00:00:00 2001 From: Ram Zallan Date: Mon, 29 Jun 2020 13:59:18 -0400 Subject: [PATCH 10/12] Generate thumbnails for PDFs from first page --- gallery/file_modules/pdf.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gallery/file_modules/pdf.py b/gallery/file_modules/pdf.py index 329009b..dcfdd54 100644 --- a/gallery/file_modules/pdf.py +++ b/gallery/file_modules/pdf.py @@ -1,4 +1,9 @@ +import os +from wand.image import Image +from wand.color import Color + from gallery.file_modules import FileModule +from gallery.util import hash_file class PDFFile(FileModule): @@ -8,3 +13,17 @@ def __init__(self, file_path, dir_path): self.mime_type = "application/pdf" self.generate_thumbnail() + + def generate_thumbnail(self): + self.thumbnail_uuid = hash_file(self.file_path) + ".jpg" + + with Image(filename=self.file_path, resolution=300) as all_pages: + with Image(all_pages.sequence[0]) as first_page: + with Image(width=first_page.width, height=first_page.height, + background=Color("#EEEEEE")) as bg: + bg.composite(first_page, 0, 0) + size = first_page.width if first_page.width < first_page.height else first_page.height + bg.crop(width=size, height=size, gravity='north') # top of first page + bg.resize(256, 256) + bg.format = 'jpeg' + bg.save(filename=os.path.join(self.dir_path, self.thumbnail_uuid)) From dda6130bcab6145750483a7b544ed86b1044e447 Mon Sep 17 00:00:00 2001 From: Ram Zallan Date: Tue, 30 Jun 2020 11:44:07 -0400 Subject: [PATCH 11/12] Add ghostscript to Dockerfile for PDF parsing --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 6a7786c..1cb5576 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ MAINTAINER Computer Science House ENV IMAGEIO_USERDIR /var/lib/gallery RUN apt-get update && \ - apt-get install -y libldap-dev libsasl2-dev libmagic-dev && \ + apt-get install -y libldap-dev libsasl2-dev libmagic-dev ghostscript && \ apt-get autoremove --yes && \ apt-get clean autoclean && \ rm -rf /var/lib/{apt,dpkg,cache,log}/ && \ From 46f4e5fd4c5302c76c7d945cc6a41c98f0accceb Mon Sep 17 00:00:00 2001 From: Max Meinhold Date: Mon, 27 Jul 2020 11:37:11 -0400 Subject: [PATCH 12/12] Bump version to 2.1.2 --- gallery/_version.py | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gallery/_version.py b/gallery/_version.py index f67c258..3fd7971 100644 --- a/gallery/_version.py +++ b/gallery/_version.py @@ -1,6 +1,6 @@ from os import environ as env -__version__ = "2.1.1" +__version__ = "2.1.2" BUILD_REFERENCE = env.get("OPENSHIFT_BUILD_REFERENCE") COMMIT_HASH = env.get("OPENSHIFT_BUILD_COMMIT") diff --git a/setup.cfg b/setup.cfg index eb28da7..4dec8a5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,7 +6,7 @@ summary = Python Photo Gallery Written in Flask url = "https://github.com/ComputerScienceHouse/gallery" description-file = README.md license = MIT -version = 2.1.1 +version = 2.1.2 classifier = Natural Language :: English Operating System :: POSIX :: Linux