From ef80c72194dd8a0b8868ece15589e0a3cf04516f Mon Sep 17 00:00:00 2001
From: Alexander Kabui
Date: Sat, 9 Oct 2021 21:55:39 +0300
Subject: unittest for processing wgcna output
---
wqflask/tests/unit/wqflask/wgcna/__init__.py | 0
wqflask/tests/unit/wqflask/wgcna/test_wgcna.py | 50 ++++++++++++++++++++++++++
2 files changed, 50 insertions(+)
create mode 100644 wqflask/tests/unit/wqflask/wgcna/__init__.py
create mode 100644 wqflask/tests/unit/wqflask/wgcna/test_wgcna.py
(limited to 'wqflask/tests')
diff --git a/wqflask/tests/unit/wqflask/wgcna/__init__.py b/wqflask/tests/unit/wqflask/wgcna/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/wqflask/tests/unit/wqflask/wgcna/test_wgcna.py b/wqflask/tests/unit/wqflask/wgcna/test_wgcna.py
new file mode 100644
index 00000000..8e947e2f
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/wgcna/test_wgcna.py
@@ -0,0 +1,50 @@
+
+"""module contains for processing gn3 wgcna data"""
+from unittest import TestCase
+
+from wqflask.wgcna.gn3_wgcna import process_wgcna_data
+
+
+class DataProcessingTests(TestCase):
+ """class contains data processing tests"""
+
+ def test_data_processing(self):
+ """test for parsing data for datatable"""
+ output = {
+ "input": {
+ "sample_names": ["BXD1", "BXD2", "BXD3", "BXD4", "BXD5", "BXD6"],
+
+ },
+ "output": {
+ "ModEigens": {
+ "MEturquoise": [
+ 0.0646677768085351,
+ 0.137200224277058,
+ 0.63451113720732,
+ -0.544002665501479,
+ -0.489487590361863,
+ 0.197111117570427
+ ],
+ "MEgrey": [
+ 0.213,
+ 0.214,
+ 0.3141,
+ -0.545,
+ -0.423,
+ 0.156,
+ ]
+ }}}
+
+ row_data = [['BXD1', 0.065, 0.213],
+ ['BXD2', 0.137, 0.214],
+ ['BXD3', 0.635, 0.314],
+ ['BXD4', -0.544, -0.545],
+ ['BXD5', -0.489, -0.423],
+ ['BXD6', 0.197, 0.156]]
+
+ expected_results = {
+ "col_names": ["sample_names", "MEturquoise", "MEgrey"],
+ "mod_dataset": row_data
+ }
+
+ self.assertEqual(process_wgcna_data(output), expected_results)
--
cgit v1.2.3
From 0c6ad845e6f461e880b423bd8f79156754658f8a Mon Sep 17 00:00:00 2001
From: BonfaceKilz
Date: Sat, 9 Oct 2021 09:43:40 +0300
Subject: Move markdown_routes to api/markdown
All new API definitions should be migrated to "wqflask/ api"
---
.../tests/unit/wqflask/api/test_markdown_routes.py | 54 ++++++
wqflask/tests/unit/wqflask/test_markdown_routes.py | 54 ------
wqflask/wqflask/__init__.py | 16 +-
wqflask/wqflask/api/correlation.py | 6 -
wqflask/wqflask/api/markdown.py | 186 +++++++++++++++++++++
wqflask/wqflask/markdown_routes.py | 186 ---------------------
6 files changed, 248 insertions(+), 254 deletions(-)
create mode 100644 wqflask/tests/unit/wqflask/api/test_markdown_routes.py
delete mode 100644 wqflask/tests/unit/wqflask/test_markdown_routes.py
create mode 100644 wqflask/wqflask/api/markdown.py
delete mode 100644 wqflask/wqflask/markdown_routes.py
(limited to 'wqflask/tests')
diff --git a/wqflask/tests/unit/wqflask/api/test_markdown_routes.py b/wqflask/tests/unit/wqflask/api/test_markdown_routes.py
new file mode 100644
index 00000000..1c513ac5
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/api/test_markdown_routes.py
@@ -0,0 +1,54 @@
+"""Test functions for wqflask/api/markdown.py"""
+
+import unittest
+from unittest import mock
+
+from dataclasses import dataclass
+from wqflask.api.markdown import render_markdown
+
+
+@dataclass
+class MockRequests404:
+ status_code: int = 404
+
+
+@dataclass
+class MockRequests200:
+ status_code: int = 200
+ content: str = b"""
+# Glossary
+This is some content
+
+## Sub-heading
+This is another sub-heading"""
+
+
+class TestMarkdownRoutesFunctions(unittest.TestCase):
+ """Test cases for functions in markdown"""
+
+ @mock.patch('wqflask.api.markdown.requests.get')
+ def test_render_markdown_when_fetching_locally(self, requests_mock):
+ requests_mock.return_value = MockRequests404()
+ markdown_content = render_markdown("general/glossary/glossary.md")
+ requests_mock.assert_called_with(
+ "https://raw.githubusercontent.com"
+ "/genenetwork/gn-docs/"
+ "master/general/"
+ "glossary/glossary.md")
+ self.assertRegexpMatches(markdown_content,
+ "Content for general/glossary/glossary.md not available.")
+
+ @mock.patch('wqflask.api.markdown.requests.get')
+ def test_render_markdown_when_fetching_remotely(self, requests_mock):
+ requests_mock.return_value = MockRequests200()
+ markdown_content = render_markdown("general/glossary/glossary.md")
+ requests_mock.assert_called_with(
+ "https://raw.githubusercontent.com"
+ "/genenetwork/gn-docs/"
+ "master/general/"
+ "glossary/glossary.md")
+ self.assertEqual("""
Glossary
+This is some content
+Sub-heading
+This is another sub-heading
""",
+ markdown_content)
diff --git a/wqflask/tests/unit/wqflask/test_markdown_routes.py b/wqflask/tests/unit/wqflask/test_markdown_routes.py
deleted file mode 100644
index 90e0f17c..00000000
--- a/wqflask/tests/unit/wqflask/test_markdown_routes.py
+++ /dev/null
@@ -1,54 +0,0 @@
-"""Test functions in markdown utils"""
-
-import unittest
-from unittest import mock
-
-from dataclasses import dataclass
-from wqflask.markdown_routes import render_markdown
-
-
-@dataclass
-class MockRequests404:
- status_code: int = 404
-
-
-@dataclass
-class MockRequests200:
- status_code: int = 200
- content: str = b"""
-# Glossary
-This is some content
-
-## Sub-heading
-This is another sub-heading"""
-
-
-class TestMarkdownRoutesFunctions(unittest.TestCase):
- """Test cases for functions in markdown_routes"""
-
- @mock.patch('wqflask.markdown_routes.requests.get')
- def test_render_markdown_when_fetching_locally(self, requests_mock):
- requests_mock.return_value = MockRequests404()
- markdown_content = render_markdown("general/glossary/glossary.md")
- requests_mock.assert_called_with(
- "https://raw.githubusercontent.com"
- "/genenetwork/gn-docs/"
- "master/general/"
- "glossary/glossary.md")
- self.assertRegexpMatches(markdown_content,
- "Content for general/glossary/glossary.md not available.")
-
- @mock.patch('wqflask.markdown_routes.requests.get')
- def test_render_markdown_when_fetching_remotely(self, requests_mock):
- requests_mock.return_value = MockRequests200()
- markdown_content = render_markdown("general/glossary/glossary.md")
- requests_mock.assert_called_with(
- "https://raw.githubusercontent.com"
- "/genenetwork/gn-docs/"
- "master/general/"
- "glossary/glossary.md")
- self.assertEqual("""Glossary
-This is some content
-Sub-heading
-This is another sub-heading
""",
- markdown_content)
diff --git a/wqflask/wqflask/__init__.py b/wqflask/wqflask/__init__.py
index 8b2055cd..5758b13e 100644
--- a/wqflask/wqflask/__init__.py
+++ b/wqflask/wqflask/__init__.py
@@ -8,14 +8,14 @@ from flask import Flask
from typing import Tuple
from urllib.parse import urlparse
from utility import formatting
-from wqflask.markdown_routes import glossary_blueprint
-from wqflask.markdown_routes import references_blueprint
-from wqflask.markdown_routes import links_blueprint
-from wqflask.markdown_routes import policies_blueprint
-from wqflask.markdown_routes import environments_blueprint
-from wqflask.markdown_routes import facilities_blueprint
-from wqflask.markdown_routes import blogs_blueprint
-from wqflask.markdown_routes import news_blueprint
+from wqflask.api.markdown import glossary_blueprint
+from wqflask.api.markdown import references_blueprint
+from wqflask.api.markdown import links_blueprint
+from wqflask.api.markdown import policies_blueprint
+from wqflask.api.markdown import environments_blueprint
+from wqflask.api.markdown import facilities_blueprint
+from wqflask.api.markdown import blogs_blueprint
+from wqflask.api.markdown import news_blueprint
app = Flask(__name__)
diff --git a/wqflask/wqflask/api/correlation.py b/wqflask/wqflask/api/correlation.py
index a135ecc8..9b875c99 100644
--- a/wqflask/wqflask/api/correlation.py
+++ b/wqflask/wqflask/api/correlation.py
@@ -9,7 +9,6 @@ from utility.db_tools import escape
from wqflask.correlation import correlation_functions
-
def do_correlation(start_vars):
assert('db' in start_vars)
assert('target_db' in start_vars)
@@ -26,7 +25,6 @@ def do_correlation(start_vars):
corr_results = calculate_results(
this_trait, this_dataset, target_dataset, corr_params)
- #corr_results = collections.OrderedDict(sorted(corr_results.items(), key=lambda t: -abs(t[1][0])))
final_results = []
for _trait_counter, trait in enumerate(list(corr_results.keys())[:corr_params['return_count']]):
@@ -54,11 +52,7 @@ def do_correlation(start_vars):
"#_strains": num_overlap,
"p_value": sample_p
}
-
final_results.append(result_dict)
-
- # json_corr_results = generate_corr_json(final_corr_results, this_trait, this_dataset, target_dataset, for_api = True)
-
return final_results
diff --git a/wqflask/wqflask/api/markdown.py b/wqflask/wqflask/api/markdown.py
new file mode 100644
index 00000000..580b9ac0
--- /dev/null
+++ b/wqflask/wqflask/api/markdown.py
@@ -0,0 +1,186 @@
+"""Markdown routes
+
+Render pages from github, or if they are unavailable, look for it else where
+"""
+
+import requests
+import markdown
+import os
+import sys
+
+from bs4 import BeautifulSoup # type: ignore
+
+from flask import send_from_directory
+from flask import Blueprint
+from flask import render_template
+
+from typing import Dict
+from typing import List
+
+glossary_blueprint = Blueprint('glossary_blueprint', __name__)
+references_blueprint = Blueprint("references_blueprint", __name__)
+environments_blueprint = Blueprint("environments_blueprint", __name__)
+links_blueprint = Blueprint("links_blueprint", __name__)
+policies_blueprint = Blueprint("policies_blueprint", __name__)
+facilities_blueprint = Blueprint("facilities_blueprint", __name__)
+news_blueprint = Blueprint("news_blueprint", __name__)
+
+blogs_blueprint = Blueprint("blogs_blueprint", __name__)
+
+
+def render_markdown(file_name, is_remote_file=True):
+ """Try to fetch the file name from Github and if that fails, try to
+look for it inside the file system """
+ github_url = ("https://raw.githubusercontent.com/"
+ "genenetwork/gn-docs/master/")
+
+ if not is_remote_file:
+ text = ""
+ with open(file_name, "r", encoding="utf-8") as input_file:
+ text = input_file.read()
+ return markdown.markdown(text,
+ extensions=['tables'])
+
+ md_content = requests.get(f"{github_url}{file_name}")
+
+ if md_content.status_code == 200:
+ return markdown.markdown(md_content.content.decode("utf-8"),
+ extensions=['tables'])
+
+ return (f"\nContent for {file_name} not available. "
+ "Please check "
+ "(here to see where content exists)"
+ "[https://github.com/genenetwork/gn-docs]. "
+ "Please reach out to the gn2 team to have a look at this")
+
+
+def get_file_from_python_search_path(pathname_suffix):
+ cands = [os.path.join(d, pathname_suffix) for d in sys.path]
+ try:
+ return list(filter(os.path.exists, cands))[0]
+ except IndexError:
+ return None
+
+
+def get_blogs(user: str = "genenetwork",
+ repo_name: str = "gn-docs") -> dict:
+
+ blogs: Dict[int, List] = {}
+ github_url = f"https://api.github.com/repos/{user}/{repo_name}/git/trees/master?recursive=1"
+
+ repo_tree = requests.get(github_url).json()["tree"]
+
+ for data in repo_tree:
+ path_name = data["path"]
+ if path_name.startswith("blog") and path_name.endswith(".md"):
+ split_path = path_name.split("/")[1:]
+ try:
+ year, title, file_name = split_path
+ except Exception as e:
+ year, file_name = split_path
+ title = ""
+
+ subtitle = os.path.splitext(file_name)[0]
+
+ blog = {
+ "title": title,
+ "subtitle": subtitle,
+ "full_path": path_name
+ }
+
+ if year in blogs:
+ blogs[int(year)].append(blog)
+ else:
+ blogs[int(year)] = [blog]
+
+ return dict(sorted(blogs.items(), key=lambda x: x[0], reverse=True))
+
+
+@glossary_blueprint.route('/')
+def glossary():
+ return render_template(
+ "glossary.html",
+ rendered_markdown=render_markdown("general/glossary/glossary.md")), 200
+
+
+@references_blueprint.route('/')
+def references():
+ return render_template(
+ "references.html",
+ rendered_markdown=render_markdown("general/references/references.md")), 200
+
+
+@news_blueprint.route('/')
+def news():
+ return render_template(
+ "news.html",
+ rendered_markdown=render_markdown("general/news/news.md")), 200
+
+
+@environments_blueprint.route("/")
+def environments():
+
+ md_file = get_file_from_python_search_path("wqflask/DEPENDENCIES.md")
+ svg_file = get_file_from_python_search_path(
+ "wqflask/dependency-graph.html")
+ svg_data = None
+ if svg_file:
+ with open(svg_file, 'r') as f:
+ svg_data = "".join(
+ BeautifulSoup(f.read(),
+ 'lxml').body.script.contents)
+
+ if md_file is not None:
+ return (
+ render_template("environment.html",
+ svg_data=svg_data,
+ rendered_markdown=render_markdown(
+ md_file,
+ is_remote_file=False)),
+ 200
+ )
+ # Fallback: Fetch file from server
+ return (render_template(
+ "environment.html",
+ svg_data=None,
+ rendered_markdown=render_markdown(
+ "general/environments/environments.md")),
+ 200)
+
+
+@environments_blueprint.route('/svg-dependency-graph')
+def svg_graph():
+ directory, file_name, _ = get_file_from_python_search_path(
+ "wqflask/dependency-graph.svg").partition("dependency-graph.svg")
+ return send_from_directory(directory, file_name)
+
+
+@links_blueprint.route("/")
+def links():
+ return render_template(
+ "links.html",
+ rendered_markdown=render_markdown("general/links/links.md")), 200
+
+
+@policies_blueprint.route("/")
+def policies():
+ return render_template(
+ "policies.html",
+ rendered_markdown=render_markdown("general/policies/policies.md")), 200
+
+
+@facilities_blueprint.route("/")
+def facilities():
+ return render_template("facilities.html", rendered_markdown=render_markdown("general/help/facilities.md")), 200
+
+
+@blogs_blueprint.route("/")
+def display_blog(blog_path):
+ return render_template("blogs.html", rendered_markdown=render_markdown(blog_path))
+
+
+@blogs_blueprint.route("/")
+def blogs_list():
+ blogs = get_blogs()
+
+ return render_template("blogs_list.html", blogs=blogs)
diff --git a/wqflask/wqflask/markdown_routes.py b/wqflask/wqflask/markdown_routes.py
deleted file mode 100644
index 580b9ac0..00000000
--- a/wqflask/wqflask/markdown_routes.py
+++ /dev/null
@@ -1,186 +0,0 @@
-"""Markdown routes
-
-Render pages from github, or if they are unavailable, look for it else where
-"""
-
-import requests
-import markdown
-import os
-import sys
-
-from bs4 import BeautifulSoup # type: ignore
-
-from flask import send_from_directory
-from flask import Blueprint
-from flask import render_template
-
-from typing import Dict
-from typing import List
-
-glossary_blueprint = Blueprint('glossary_blueprint', __name__)
-references_blueprint = Blueprint("references_blueprint", __name__)
-environments_blueprint = Blueprint("environments_blueprint", __name__)
-links_blueprint = Blueprint("links_blueprint", __name__)
-policies_blueprint = Blueprint("policies_blueprint", __name__)
-facilities_blueprint = Blueprint("facilities_blueprint", __name__)
-news_blueprint = Blueprint("news_blueprint", __name__)
-
-blogs_blueprint = Blueprint("blogs_blueprint", __name__)
-
-
-def render_markdown(file_name, is_remote_file=True):
- """Try to fetch the file name from Github and if that fails, try to
-look for it inside the file system """
- github_url = ("https://raw.githubusercontent.com/"
- "genenetwork/gn-docs/master/")
-
- if not is_remote_file:
- text = ""
- with open(file_name, "r", encoding="utf-8") as input_file:
- text = input_file.read()
- return markdown.markdown(text,
- extensions=['tables'])
-
- md_content = requests.get(f"{github_url}{file_name}")
-
- if md_content.status_code == 200:
- return markdown.markdown(md_content.content.decode("utf-8"),
- extensions=['tables'])
-
- return (f"\nContent for {file_name} not available. "
- "Please check "
- "(here to see where content exists)"
- "[https://github.com/genenetwork/gn-docs]. "
- "Please reach out to the gn2 team to have a look at this")
-
-
-def get_file_from_python_search_path(pathname_suffix):
- cands = [os.path.join(d, pathname_suffix) for d in sys.path]
- try:
- return list(filter(os.path.exists, cands))[0]
- except IndexError:
- return None
-
-
-def get_blogs(user: str = "genenetwork",
- repo_name: str = "gn-docs") -> dict:
-
- blogs: Dict[int, List] = {}
- github_url = f"https://api.github.com/repos/{user}/{repo_name}/git/trees/master?recursive=1"
-
- repo_tree = requests.get(github_url).json()["tree"]
-
- for data in repo_tree:
- path_name = data["path"]
- if path_name.startswith("blog") and path_name.endswith(".md"):
- split_path = path_name.split("/")[1:]
- try:
- year, title, file_name = split_path
- except Exception as e:
- year, file_name = split_path
- title = ""
-
- subtitle = os.path.splitext(file_name)[0]
-
- blog = {
- "title": title,
- "subtitle": subtitle,
- "full_path": path_name
- }
-
- if year in blogs:
- blogs[int(year)].append(blog)
- else:
- blogs[int(year)] = [blog]
-
- return dict(sorted(blogs.items(), key=lambda x: x[0], reverse=True))
-
-
-@glossary_blueprint.route('/')
-def glossary():
- return render_template(
- "glossary.html",
- rendered_markdown=render_markdown("general/glossary/glossary.md")), 200
-
-
-@references_blueprint.route('/')
-def references():
- return render_template(
- "references.html",
- rendered_markdown=render_markdown("general/references/references.md")), 200
-
-
-@news_blueprint.route('/')
-def news():
- return render_template(
- "news.html",
- rendered_markdown=render_markdown("general/news/news.md")), 200
-
-
-@environments_blueprint.route("/")
-def environments():
-
- md_file = get_file_from_python_search_path("wqflask/DEPENDENCIES.md")
- svg_file = get_file_from_python_search_path(
- "wqflask/dependency-graph.html")
- svg_data = None
- if svg_file:
- with open(svg_file, 'r') as f:
- svg_data = "".join(
- BeautifulSoup(f.read(),
- 'lxml').body.script.contents)
-
- if md_file is not None:
- return (
- render_template("environment.html",
- svg_data=svg_data,
- rendered_markdown=render_markdown(
- md_file,
- is_remote_file=False)),
- 200
- )
- # Fallback: Fetch file from server
- return (render_template(
- "environment.html",
- svg_data=None,
- rendered_markdown=render_markdown(
- "general/environments/environments.md")),
- 200)
-
-
-@environments_blueprint.route('/svg-dependency-graph')
-def svg_graph():
- directory, file_name, _ = get_file_from_python_search_path(
- "wqflask/dependency-graph.svg").partition("dependency-graph.svg")
- return send_from_directory(directory, file_name)
-
-
-@links_blueprint.route("/")
-def links():
- return render_template(
- "links.html",
- rendered_markdown=render_markdown("general/links/links.md")), 200
-
-
-@policies_blueprint.route("/")
-def policies():
- return render_template(
- "policies.html",
- rendered_markdown=render_markdown("general/policies/policies.md")), 200
-
-
-@facilities_blueprint.route("/")
-def facilities():
- return render_template("facilities.html", rendered_markdown=render_markdown("general/help/facilities.md")), 200
-
-
-@blogs_blueprint.route("/")
-def display_blog(blog_path):
- return render_template("blogs.html", rendered_markdown=render_markdown(blog_path))
-
-
-@blogs_blueprint.route("/")
-def blogs_list():
- blogs = get_blogs()
-
- return render_template("blogs_list.html", blogs=blogs)
--
cgit v1.2.3
From 212d19c29a42bd6966965b166cdbb4dd642e5eb4 Mon Sep 17 00:00:00 2001
From: BonfaceKilz
Date: Wed, 13 Oct 2021 13:05:26 +0300
Subject: Add test-cases for `get_user_membership`
---
.../tests/unit/wqflask/test_resource_manager.py | 51 ++++++++++++++++++++++
1 file changed, 51 insertions(+)
create mode 100644 wqflask/tests/unit/wqflask/test_resource_manager.py
(limited to 'wqflask/tests')
diff --git a/wqflask/tests/unit/wqflask/test_resource_manager.py b/wqflask/tests/unit/wqflask/test_resource_manager.py
new file mode 100644
index 00000000..a27f40e1
--- /dev/null
+++ b/wqflask/tests/unit/wqflask/test_resource_manager.py
@@ -0,0 +1,51 @@
+"""Test cases for wqflask/resource_manager.py"""
+import unittest
+
+from unittest import mock
+from wqflask.resource_manager import get_user_membership
+
+
+class TestGetUserMembership(unittest.TestCase):
+ """Test cases for `get_user_membership`"""
+
+ def setUp(self):
+ conn = mock.MagicMock()
+ conn.hgetall.return_value = {
+ '7fa95d07-0e2d-4bc5-b47c-448fdc1260b2': (
+ '{"name": "editors", '
+ '"admins": ["8ad942fe-490d-453e-bd37-56f252e41604", "rand"], '
+ '"members": ["8ad942fe-490d-453e-bd37-56f252e41603", '
+ '"rand"], '
+ '"changed_timestamp": "Oct 06 2021 06:39PM", '
+ '"created_timestamp": "Oct 06 2021 06:39PM"}')}
+ self.conn = conn
+
+ def test_user_is_group_member_only(self):
+ """Test that a user is only a group member"""
+ self.assertEqual(
+ get_user_membership(
+ conn=self.conn,
+ user_id="8ad942fe-490d-453e-bd37-56f252e41603",
+ group_id="7fa95d07-0e2d-4bc5-b47c-448fdc1260b2"),
+ {"member": True,
+ "admin": False})
+
+ def test_user_is_group_admin_only(self):
+ """Test that a user is a group admin only"""
+ self.assertEqual(
+ get_user_membership(
+ conn=self.conn,
+ user_id="8ad942fe-490d-453e-bd37-56f252e41604",
+ group_id="7fa95d07-0e2d-4bc5-b47c-448fdc1260b2"),
+ {"member": False,
+ "admin": True})
+
+ def test_user_is_both_group_member_and_admin(self):
+ """Test that a user is both an admin and member of a group"""
+ self.assertEqual(
+ get_user_membership(
+ conn=self.conn,
+ user_id="rand",
+ group_id="7fa95d07-0e2d-4bc5-b47c-448fdc1260b2"),
+ {"member": True,
+ "admin": True})
--
cgit v1.2.3
From 610335cb3c3030cf39e91ad3232d468b388fc340 Mon Sep 17 00:00:00 2001
From: BonfaceKilz
Date: Fri, 15 Oct 2021 08:51:46 +0300
Subject: Get a users access mask
If a user has several access roles, select the highest role.
---
.../tests/unit/wqflask/test_resource_manager.py | 59 ++++++++++++++++++++++
wqflask/wqflask/resource_manager.py | 48 ++++++++++++++++++
2 files changed, 107 insertions(+)
(limited to 'wqflask/tests')
diff --git a/wqflask/tests/unit/wqflask/test_resource_manager.py b/wqflask/tests/unit/wqflask/test_resource_manager.py
index a27f40e1..b0b7e6a3 100644
--- a/wqflask/tests/unit/wqflask/test_resource_manager.py
+++ b/wqflask/tests/unit/wqflask/test_resource_manager.py
@@ -3,6 +3,9 @@ import unittest
from unittest import mock
from wqflask.resource_manager import get_user_membership
+from wqflask.resource_manager import get_user_access_roles
+from wqflask.resource_manager import DataRole
+from wqflask.resource_manager import AdminRole
class TestGetUserMembership(unittest.TestCase):
@@ -49,3 +52,59 @@ class TestGetUserMembership(unittest.TestCase):
group_id="7fa95d07-0e2d-4bc5-b47c-448fdc1260b2"),
{"member": True,
"admin": True})
+
+
+class TestCheckUserAccessRole(unittest.TestCase):
+ """Test cases for `get_user_access_roles`"""
+
+ def setUp(self):
+ conn = mock.MagicMock()
+ conn.hget.return_value = (
+ '{"owner_id": "8ad942fe-490d-453e-bd37", '
+ '"default_mask": {"data": "no-access", '
+ '"metadata": "no-access", '
+ '"admin": "not-admin"}, '
+ '"group_masks": '
+ '{"7fa95d07-0e2d-4bc5-b47c-448fdc1260b2": '
+ '{"metadata": "edit", "data": "edit"}}, '
+ '"name": "_14329", "'
+ 'data": {"dataset": 1, "trait": 14329}, '
+ '"type": "dataset-publish"}')
+
+ conn.hgetall.return_value = {
+ '7fa95d07-0e2d-4bc5-b47c-448fdc1260b2': (
+ '{"name": "editors", '
+ '"admins": ["8ad942fe-490d-453e-bd37-56f252e41604", "rand"], '
+ '"members": ["8ad942fe-490d-453e-bd37-56f252e41603", '
+ '"rand"], '
+ '"changed_timestamp": "Oct 06 2021 06:39PM", '
+ '"created_timestamp": "Oct 06 2021 06:39PM"}')}
+ self.conn = conn
+
+ def test_get_user_access_when_owner(self):
+ """Test that the right access roles are set"""
+ self.assertEqual(get_user_access_roles(
+ conn=self.conn,
+ resource_id="", # Can be anything
+ user_id="8ad942fe-490d-453e-bd37"),
+ {"data": DataRole.EDIT,
+ "metadata": DataRole.EDIT,
+ "admin": AdminRole.EDIT_ACCESS})
+
+ def test_get_user_access_default_mask(self):
+ self.assertEqual(get_user_access_roles(
+ conn=self.conn,
+ resource_id="", # Can be anything
+ user_id=""),
+ {"data": DataRole.NO_ACCESS,
+ "metadata": DataRole.NO_ACCESS,
+ "admin": AdminRole.NOT_ADMIN})
+
+ def test_get_user_access_group_mask(self):
+ self.assertEqual(get_user_access_roles(
+ conn=self.conn,
+ resource_id="", # Can be anything
+ user_id="8ad942fe-490d-453e-bd37-56f252e41603"),
+ {"data": DataRole.EDIT,
+ "metadata": DataRole.EDIT,
+ "admin": AdminRole.NOT_ADMIN})
diff --git a/wqflask/wqflask/resource_manager.py b/wqflask/wqflask/resource_manager.py
index 7f4718f0..a3a94f9e 100644
--- a/wqflask/wqflask/resource_manager.py
+++ b/wqflask/wqflask/resource_manager.py
@@ -63,4 +63,52 @@ def get_user_membership(conn: redis.Redis, user_id: str,
results["member"] = True
break
return results
+
+
+def get_user_access_roles(conn: redis.Redis,
+ resource_id: str,
+ user_id: str) -> Dict:
+ """Get the highest access roles for a given user
+
+ Args:
+ - conn: A redis connection with `decoded_responses == True`.
+ - resource_id: The unique id of a given resource.
+
+ Returns:
+ A dict indicating the highest access role the user has.
+ """
+ # This is the default access role
+ access_role = {
+ "data": [DataRole.NO_ACCESS],
+ "metadata": [DataRole.NO_ACCESS],
+ "admin": [AdminRole.NOT_ADMIN],
+ }
+ resource_info = json.loads(conn.hget('resources', resource_id))
+
+ # Check the resource's default mask
+ if default_mask := resource_info.get("default_mask"):
+ access_role["data"].append(DataRole(default_mask.get("data")))
+ access_role["metadata"].append(DataRole(default_mask.get("metadata")))
+ access_role["admin"].append(AdminRole(default_mask.get("admin")))
+
+ # Then check if the user is the owner Check with Zach and Rob if
+ # the owner, be default should, as the lowest access_roles, edit
+ # access
+ if resource_info.get("owner_id") == user_id:
+ access_role["data"].append(DataRole.EDIT)
+ access_role["metadata"].append(DataRole.EDIT)
+ access_role["admin"].append(AdminRole.EDIT_ACCESS)
+
+ # Check the group mask. If the user is in that group mask, use the
+ # access roles for that group
+ if group_masks := resource_info.get("group_masks"):
+ for group_id, roles in group_masks.items():
+ user_membership = get_user_membership(conn=conn,
+ user_id=user_id,
+ group_id=group_id)
+ if any(user_membership.values()):
+ access_role["data"].append(DataRole(roles.get("data")))
+ access_role["metadata"].append(
+ DataRole(roles.get("metadata")))
+ return {k: max(v) for k, v in access_role.items()}
admin_status = check_owner_or_admin(resource_id=resource_id)
--
cgit v1.2.3
From da86bc79798c05ec469d76f375741f306213e4d0 Mon Sep 17 00:00:00 2001
From: BonfaceKilz
Date: Fri, 15 Oct 2021 13:01:38 +0300
Subject: Replace "resource_id" with "resource_info" dict
This avoids calling Redis twice when fetching metadata about the
resource.
---
.../tests/unit/wqflask/test_resource_manager.py | 36 +++++++++++++---------
wqflask/wqflask/resource_manager.py | 10 +++---
2 files changed, 28 insertions(+), 18 deletions(-)
(limited to 'wqflask/tests')
diff --git a/wqflask/tests/unit/wqflask/test_resource_manager.py b/wqflask/tests/unit/wqflask/test_resource_manager.py
index b0b7e6a3..9d5aaf0b 100644
--- a/wqflask/tests/unit/wqflask/test_resource_manager.py
+++ b/wqflask/tests/unit/wqflask/test_resource_manager.py
@@ -58,18 +58,26 @@ class TestCheckUserAccessRole(unittest.TestCase):
"""Test cases for `get_user_access_roles`"""
def setUp(self):
+ self.resource_info = {
+ "owner_id": "8ad942fe-490d-453e-bd37",
+ "default_mask": {
+ "data": "no-access",
+ "metadata": "no-access",
+ "admin": "not-admin",
+ },
+ "group_masks": {
+ "7fa95d07-0e2d-4bc5-b47c-448fdc1260b2": {
+ "metadata": "edit",
+ "data": "edit",
+ }},
+ "name": "_14329",
+ "data": {
+ "dataset": 1,
+ "trait": 14329,
+ },
+ "type": "dataset-publish",
+ }
conn = mock.MagicMock()
- conn.hget.return_value = (
- '{"owner_id": "8ad942fe-490d-453e-bd37", '
- '"default_mask": {"data": "no-access", '
- '"metadata": "no-access", '
- '"admin": "not-admin"}, '
- '"group_masks": '
- '{"7fa95d07-0e2d-4bc5-b47c-448fdc1260b2": '
- '{"metadata": "edit", "data": "edit"}}, '
- '"name": "_14329", "'
- 'data": {"dataset": 1, "trait": 14329}, '
- '"type": "dataset-publish"}')
conn.hgetall.return_value = {
'7fa95d07-0e2d-4bc5-b47c-448fdc1260b2': (
@@ -85,7 +93,7 @@ class TestCheckUserAccessRole(unittest.TestCase):
"""Test that the right access roles are set"""
self.assertEqual(get_user_access_roles(
conn=self.conn,
- resource_id="", # Can be anything
+ resource_info=self.resource_info,
user_id="8ad942fe-490d-453e-bd37"),
{"data": DataRole.EDIT,
"metadata": DataRole.EDIT,
@@ -94,7 +102,7 @@ class TestCheckUserAccessRole(unittest.TestCase):
def test_get_user_access_default_mask(self):
self.assertEqual(get_user_access_roles(
conn=self.conn,
- resource_id="", # Can be anything
+ resource_info=self.resource_info,
user_id=""),
{"data": DataRole.NO_ACCESS,
"metadata": DataRole.NO_ACCESS,
@@ -103,7 +111,7 @@ class TestCheckUserAccessRole(unittest.TestCase):
def test_get_user_access_group_mask(self):
self.assertEqual(get_user_access_roles(
conn=self.conn,
- resource_id="", # Can be anything
+ resource_info=self.resource_info,
user_id="8ad942fe-490d-453e-bd37-56f252e41603"),
{"data": DataRole.EDIT,
"metadata": DataRole.EDIT,
diff --git a/wqflask/wqflask/resource_manager.py b/wqflask/wqflask/resource_manager.py
index a3a94f9e..57b99296 100644
--- a/wqflask/wqflask/resource_manager.py
+++ b/wqflask/wqflask/resource_manager.py
@@ -66,16 +66,19 @@ def get_user_membership(conn: redis.Redis, user_id: str,
def get_user_access_roles(conn: redis.Redis,
- resource_id: str,
+ resource_info: Dict,
user_id: str) -> Dict:
"""Get the highest access roles for a given user
Args:
- - conn: A redis connection with `decoded_responses == True`.
- - resource_id: The unique id of a given resource.
+ - conn: A redis connection with the responses decoded.
+ - resource_info: A dict containing details(metadata) about a
+ given resource.
+ - user_id: The unique id of a given user.
Returns:
A dict indicating the highest access role the user has.
+
"""
# This is the default access role
access_role = {
@@ -83,7 +86,6 @@ def get_user_access_roles(conn: redis.Redis,
"metadata": [DataRole.NO_ACCESS],
"admin": [AdminRole.NOT_ADMIN],
}
- resource_info = json.loads(conn.hget('resources', resource_id))
# Check the resource's default mask
if default_mask := resource_info.get("default_mask"):
--
cgit v1.2.3
From fbffb2e4f7538cc34332f37064d4b67cd52588fb Mon Sep 17 00:00:00 2001
From: BonfaceKilz
Date: Wed, 20 Oct 2021 13:43:57 +0300
Subject: Update failing tests when testing `get_user_access_roles`
---
.../tests/unit/wqflask/test_resource_manager.py | 82 ++++++++--------------
1 file changed, 29 insertions(+), 53 deletions(-)
(limited to 'wqflask/tests')
diff --git a/wqflask/tests/unit/wqflask/test_resource_manager.py b/wqflask/tests/unit/wqflask/test_resource_manager.py
index 9d5aaf0b..01fb2021 100644
--- a/wqflask/tests/unit/wqflask/test_resource_manager.py
+++ b/wqflask/tests/unit/wqflask/test_resource_manager.py
@@ -1,4 +1,5 @@
"""Test cases for wqflask/resource_manager.py"""
+import json
import unittest
from unittest import mock
@@ -57,62 +58,37 @@ class TestGetUserMembership(unittest.TestCase):
class TestCheckUserAccessRole(unittest.TestCase):
"""Test cases for `get_user_access_roles`"""
- def setUp(self):
- self.resource_info = {
- "owner_id": "8ad942fe-490d-453e-bd37",
- "default_mask": {
- "data": "no-access",
- "metadata": "no-access",
- "admin": "not-admin",
- },
- "group_masks": {
- "7fa95d07-0e2d-4bc5-b47c-448fdc1260b2": {
- "metadata": "edit",
- "data": "edit",
- }},
- "name": "_14329",
- "data": {
- "dataset": 1,
- "trait": 14329,
- },
- "type": "dataset-publish",
- }
- conn = mock.MagicMock()
-
- conn.hgetall.return_value = {
- '7fa95d07-0e2d-4bc5-b47c-448fdc1260b2': (
- '{"name": "editors", '
- '"admins": ["8ad942fe-490d-453e-bd37-56f252e41604", "rand"], '
- '"members": ["8ad942fe-490d-453e-bd37-56f252e41603", '
- '"rand"], '
- '"changed_timestamp": "Oct 06 2021 06:39PM", '
- '"created_timestamp": "Oct 06 2021 06:39PM"}')}
- self.conn = conn
-
- def test_get_user_access_when_owner(self):
+ @mock.patch("wqflask.resource_manager.requests.get")
+ def test_edit_access(self, requests_mock):
"""Test that the right access roles are set"""
+ response = mock.PropertyMock(return_value=json.dumps(
+ {
+ 'data': ['no-access', 'view', 'edit', ],
+ 'metadata': ['no-access', 'view', 'edit', ],
+ 'admin': ['not-admin', 'edit-access', ],
+ }
+ ))
+ type(requests_mock.return_value).content = response
self.assertEqual(get_user_access_roles(
- conn=self.conn,
- resource_info=self.resource_info,
+ resource_id="0196d92e1665091f202f",
user_id="8ad942fe-490d-453e-bd37"),
- {"data": DataRole.EDIT,
- "metadata": DataRole.EDIT,
- "admin": AdminRole.EDIT_ACCESS})
+ {"data": DataRole.EDIT,
+ "metadata": DataRole.EDIT,
+ "admin": AdminRole.EDIT_ACCESS})
- def test_get_user_access_default_mask(self):
+ @mock.patch("wqflask.resource_manager.requests.get")
+ def test_no_access(self, requests_mock):
+ response = mock.PropertyMock(return_value=json.dumps(
+ {
+ 'data': ['no-access', ],
+ 'metadata': ['no-access', ],
+ 'admin': ['not-admin', ],
+ }
+ ))
+ type(requests_mock.return_value).content = response
self.assertEqual(get_user_access_roles(
- conn=self.conn,
- resource_info=self.resource_info,
+ resource_id="0196d92e1665091f202f",
user_id=""),
- {"data": DataRole.NO_ACCESS,
- "metadata": DataRole.NO_ACCESS,
- "admin": AdminRole.NOT_ADMIN})
-
- def test_get_user_access_group_mask(self):
- self.assertEqual(get_user_access_roles(
- conn=self.conn,
- resource_info=self.resource_info,
- user_id="8ad942fe-490d-453e-bd37-56f252e41603"),
- {"data": DataRole.EDIT,
- "metadata": DataRole.EDIT,
- "admin": AdminRole.NOT_ADMIN})
+ {"data": DataRole.NO_ACCESS,
+ "metadata": DataRole.NO_ACCESS,
+ "admin": AdminRole.NOT_ADMIN})
--
cgit v1.2.3
From b3a9b90343f70584b82df00a42cbcc5b97dbfc7f Mon Sep 17 00:00:00 2001
From: BonfaceKilz
Date: Mon, 1 Nov 2021 09:22:23 +0300
Subject: use gn3 imports
---
wqflask/tests/unit/wqflask/test_resource_manager.py | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
(limited to 'wqflask/tests')
diff --git a/wqflask/tests/unit/wqflask/test_resource_manager.py b/wqflask/tests/unit/wqflask/test_resource_manager.py
index 01fb2021..f4335425 100644
--- a/wqflask/tests/unit/wqflask/test_resource_manager.py
+++ b/wqflask/tests/unit/wqflask/test_resource_manager.py
@@ -3,10 +3,10 @@ import json
import unittest
from unittest import mock
-from wqflask.resource_manager import get_user_membership
-from wqflask.resource_manager import get_user_access_roles
-from wqflask.resource_manager import DataRole
-from wqflask.resource_manager import AdminRole
+from gn3.authentication import get_user_membership
+from gn3.authentication import get_highest_user_access_role
+from gn3.authentication import DataRole
+from gn3.authentication import AdminRole
class TestGetUserMembership(unittest.TestCase):
@@ -56,7 +56,7 @@ class TestGetUserMembership(unittest.TestCase):
class TestCheckUserAccessRole(unittest.TestCase):
- """Test cases for `get_user_access_roles`"""
+ """Test cases for `get_highest_user_access_role`"""
@mock.patch("wqflask.resource_manager.requests.get")
def test_edit_access(self, requests_mock):
@@ -69,7 +69,7 @@ class TestCheckUserAccessRole(unittest.TestCase):
}
))
type(requests_mock.return_value).content = response
- self.assertEqual(get_user_access_roles(
+ self.assertEqual(get_highest_user_access_role(
resource_id="0196d92e1665091f202f",
user_id="8ad942fe-490d-453e-bd37"),
{"data": DataRole.EDIT,
@@ -86,7 +86,7 @@ class TestCheckUserAccessRole(unittest.TestCase):
}
))
type(requests_mock.return_value).content = response
- self.assertEqual(get_user_access_roles(
+ self.assertEqual(get_highest_user_access_role(
resource_id="0196d92e1665091f202f",
user_id=""),
{"data": DataRole.NO_ACCESS,
--
cgit v1.2.3