diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 78d9bcc1c..930d883b5 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -17,12 +17,13 @@ - [ ] Bug fix (non-breaking) - [ ] New feature (non-breaking) - [ ] Breaking change (breaking, will cause existing functionality to not work as expected) +- [ ] Tests (only) # Checklist: ## General -- [ ] [Changelog](../CHANGELOG.md): New row added +- [ ] [Changelog](../CHANGELOG.md): New row added. Not needed when PR includes _only_ tests. - [ ] Database schema has changed - [ ] A new migration is included in the PR - [ ] The change does not require a migration @@ -35,10 +36,13 @@ - [ ] Blocking PRs have been merged - [ ] Rebase / update of branch done -- [ ] Product Owner / Scrum Master - - [ ] The [version](../dds_web/version.py) is updated (PR to `master` branch) - - [ ] I am bumping the major version (e.g. 1.x.x to 2.x.x) - - [ ] I have made the corresponding changes to the CLI version +- [ ] PR to `master` branch (Product Owner / Scrum Master) + - [ ] The [version](../dds_web/version.py) is updated + - [ ] I am bumping the major version (e.g. 1.x.x to 2.x.x) + - [ ] I have made the corresponding changes to the CLI version + - [ ] Backward compatible + - [ ] Yes: The code works together with `dds_cli/master` branch + - [ ] No: The code **does not** entirely / at all work together with the `dds_cli/master` branch. _Please add detailed and clear information about the broken features_ ## Checks diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 27b5af07d..fbeb0ab63 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -28,7 +28,9 @@ jobs: actions: read contents: read security-events: write - + concurrency: + group: ${{ github.ref }}-codeql + cancel-in-progress: true strategy: fail-fast: false matrix: diff --git a/.github/workflows/docker-compose-tests.yml b/.github/workflows/docker-compose-tests.yml index 276c2fade..5f6444ac4 100644 --- a/.github/workflows/docker-compose-tests.yml +++ b/.github/workflows/docker-compose-tests.yml @@ -8,6 +8,9 @@ on: jobs: pytest: + concurrency: + group: ${{ github.ref }}-pytest + cancel-in-progress: true runs-on: ubuntu-latest steps: diff --git a/.github/workflows/publish_and_trivyscan.yml b/.github/workflows/publish_and_trivyscan.yml index f3d4249a3..909d89d8f 100644 --- a/.github/workflows/publish_and_trivyscan.yml +++ b/.github/workflows/publish_and_trivyscan.yml @@ -13,6 +13,13 @@ jobs: if: github.repository == 'ScilifelabDataCentre/dds_web' name: Push Docker image to Docker Hub runs-on: ubuntu-latest + permissions: + contents: read + packages: write + security-events: write + concurrency: + group: ${{ github.ref }}-docker-trivy + cancel-in-progress: true steps: - name: Check out the repo uses: actions/checkout@v2 @@ -61,5 +68,6 @@ jobs: file: Dockerfiles/backend.Dockerfile context: . push: true + build-args: version=${{ github.ref_name }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index 30f65dbde..09abfd196 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -20,7 +20,7 @@ jobs: - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@0.7.1 with: - image-ref: "ghcr.io/${{ env.REPOSITORY_OWNER }}/dds-backend:dev" + image-ref: "ghcr.io/${{ env.REPOSITORY_OWNER }}/dds-backend:latest" format: "sarif" output: "trivy-results.sarif" severity: "CRITICAL,HIGH" diff --git a/CHANGELOG.md b/CHANGELOG.md index 253cd3fcb..661bafb00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Data Delivery System Web / API: Changelog -Please add a _short_ line describing the PR you make, if the PR implements a specific feature or functionality, or refactor. Not needed if you add very small and unnoticable changes. +Please add a _short_ line describing the PR you make, if the PR implements a specific feature or functionality, or refactor. Not needed if you add very small and unnoticable changes. Not needed when PR includes _only_ tests for already existing feature. ## Sprint (2022-02-09 - 2022-02-23) @@ -151,3 +151,16 @@ Please add a _short_ line describing the PR you make, if the PR implements a spe - New table: `Maintenance`, for keeping track of DDS maintenance mode ([#1284](https://github.com/ScilifelabDataCentre/dds_web/pull/1284)) - New endpoint: SetMaintenance - set maintenance mode to on or off ([#1286](https://github.com/ScilifelabDataCentre/dds_web/pull/1286)) - New endpoint: AnyProjectsBusy - check if any projects are busy in DDS ([#1288](https://github.com/ScilifelabDataCentre/dds_web/pull/1288)) + +## Sprint (2022-09-30 - 2022-10-14) + +- Bug fix: Fix the Invite.projects database model ([#1290](https://github.com/ScilifelabDataCentre/dds_web/pull/1290)) +- New endpoint: ListInvites - list invites ([#1294](https://github.com/ScilifelabDataCentre/dds_web/pull/1294)) + +## Sprint (2022-10-14 - 2022-10-28) + +- Limit projects listing to active projects only; a `--show-all` flag can be used for listing all projects, active and inactive ([#1302](https://github.com/ScilifelabDataCentre/dds_web/pull/1302)) +- Return name of project creator from UserProjects ([#1303](https://github.com/ScilifelabDataCentre/dds_web/pull/1303)) +- Add version to the footer of the web pages ([#1304](https://github.com/ScilifelabDataCentre/dds_web/pull/1304)) +- Add link to the dds instance to the end of all emails ([#1305](https://github.com/ScilifelabDataCentre/dds_web/pull/1305)) +- Troubleshooting steps added to web page ([#1309](https://github.com/ScilifelabDataCentre/dds_web/pull/1309)) diff --git a/Dockerfiles/backend.Dockerfile b/Dockerfiles/backend.Dockerfile index 954690583..9db625df5 100644 --- a/Dockerfiles/backend.Dockerfile +++ b/Dockerfiles/backend.Dockerfile @@ -19,6 +19,10 @@ RUN apk add jpeg-dev zlib-dev libjpeg RUN apk add tzdata ENV TZ="UCT" +# Extract version from Github during build +ARG version +ENV DDS_VERSION=$version + # Copy the content to a code folder in container COPY ./requirements.txt /code/requirements.txt diff --git a/dds_web/__init__.py b/dds_web/__init__.py index d0c6be831..a88ee4d61 100644 --- a/dds_web/__init__.py +++ b/dds_web/__init__.py @@ -36,7 +36,6 @@ from dds_web.scheduled_tasks import scheduler - #################################################################################################### # GLOBAL VARIABLES ############################################################## GLOBAL VARIABLES # #################################################################################################### @@ -190,11 +189,11 @@ def create_app(testing=False, database_uri=None): @app.before_request def prepare(): """Populate flask globals for template rendering""" - from dds_web.utils import verify_cli_version - from dds_web.utils import get_active_motds + from dds_web.utils import verify_cli_version, get_active_motds, block_if_maintenance # Verify cli version compatible if "api/v1" in flask.request.path: + block_if_maintenance() verify_cli_version(version_cli=flask.request.headers.get("X-Cli-Version")) # Get message of the day @@ -272,6 +271,11 @@ def load_user(user_id): app.cli.add_command(update_uploaded_file_with_log) app.cli.add_command(lost_files_s3_db) + # Make version available inside jinja templates: + @app.template_filter("dds_version") + def dds_version_filter(_): + return os.environ.get("DDS_VERSION", "Unknown") + with app.app_context(): # Everything in here has access to sessions from dds_web.database import models @@ -312,21 +316,6 @@ def load_user(user_id): def fill_db_wrapper(db_type): from dds_web.database import models - maintenance_active: bool = db_type == "production" - flask.current_app.logger.info( - f"Setting maintenance as {'active' if maintenance_active else 'inactive'}..." - ) - - old_maintenance: models.Maintenance = models.Maintenance.query.all() - if len(old_maintenance) > 1: - for row in old_maintenance[1::]: - db.session.delete(row) - old_maintenance[0].active = maintenance_active - else: - new_maintenance: models.Maintenance = models.Maintenance(active=maintenance_active) - db.session.add(new_maintenance) - db.session.commit() - if db_type == "production": username = flask.current_app.config["SUPERADMIN_USERNAME"] password = flask.current_app.config["SUPERADMIN_PASSWORD"] diff --git a/dds_web/api/__init__.py b/dds_web/api/__init__.py index 0ebc5aeaf..5168f6beb 100644 --- a/dds_web/api/__init__.py +++ b/dds_web/api/__init__.py @@ -76,6 +76,7 @@ def output_json(data, code, headers=None): user.RequestTOTPActivation, "/user/totp/activate", endpoint="request_totp_activation" ) api.add_resource(user.Users, "/users", endpoint="users") +api.add_resource(user.InvitedUsers, "/user/invites", endpoint="list_invites") # Super Admins ###################################################################### Super Admins # diff --git a/dds_web/api/project.py b/dds_web/api/project.py index 1bd40111b..f6ee47f37 100644 --- a/dds_web/api/project.py +++ b/dds_web/api/project.py @@ -472,14 +472,27 @@ def format_project_dict(self, current_user): "Unit Personnel", ] + # Get info for projects + get_all = flask.request.json.get("show_all", False) if flask.request.json else False + all_filters = ( + [] if get_all else [models.Project.is_active == True] + ) # Default is to only get active projects + all_filters.append( + models.Project.public_id.in_([x.public_id for x in current_user.projects]) + ) + + # Apply the filters + user_projects = models.Project.query.filter(sqlalchemy.and_(*all_filters)).all() + # Get info for all projects - for p in current_user.projects: + for p in user_projects: project_info = { "Project ID": p.public_id, "Title": p.title, "PI": p.pi, "Status": p.current_status, "Last updated": p.date_updated if p.date_updated else p.date_created, + "Created by": p.creator.name, } # Get proj size and update total size diff --git a/dds_web/api/user.py b/dds_web/api/user.py index bf6e47a68..27c6e6b95 100644 --- a/dds_web/api/user.py +++ b/dds_web/api/user.py @@ -1254,3 +1254,99 @@ def get_users(unit: models.Unit = None): "keys": keys, "empty": not users_to_return, } + + +class InvitedUsers(flask_restful.Resource): + """Provide a list of invited users.""" + + @auth.login_required + def get(self): + current_user = auth.current_user() + + # columns to return, map to displayed column names + key_map = { + "email": "Email", + "role": "Role", + "created_at": "Created", + "projects": "Projects", + } + key_order = [key_map["email"], key_map["role"], key_map["projects"], key_map["created_at"]] + if current_user.role == "Super Admin": + key_map["unit"] = "Unit" + key_order.insert(1, "Unit") + + def row_to_dict(entry) -> dict: + """Convert a db row to a dict, extracting only wanted columns.""" + hit = {} + for key in key_map.keys(): + hit[key_map[key]] = getattr(entry, key) or "" + # represent projects with public_id + hit["Projects"] = [project.public_id for project in hit["Projects"]] + # represent unit with name + if hit.get("Unit"): + hit["Unit"] = hit["Unit"].name + return hit + + if current_user.role == "Super Admin": + # superadmin can see all invites + raw_invites = models.Invite.query.all() + hits = [] + for inv in raw_invites: + entry = row_to_dict(inv) + if inv.role == "Super Admin": + entry["Projects"] = "----" + hits.append(entry) + + elif current_user.role in ("Unit Admin", "Unit Personnel"): + # unit users can see all invites to the unit and any projects it owns + # start by getting all invites, then filter by project and unit + unit = current_user.unit + unit_projects = set(proj.id for proj in unit.projects) + unit_projects_pubid = set(proj.public_id for proj in unit.projects) + raw_invites = models.Invite.query.all() + hits = [] + for inv in raw_invites: + if inv.role == "Researcher" and set(proj.id for proj in inv.projects).intersection( + unit_projects + ): + entry = row_to_dict(inv) + # do not list projects the unit does not own + entry["Projects"] = [ + project for project in entry["Projects"] if project in unit_projects_pubid + ] + hits.append(entry) + elif inv.role in ("Unit Admin", "Unit Personnel") and inv.unit == unit: + hits.append(row_to_dict(inv)) + + elif current_user.role == "Researcher": + # researchers can see invitations to projects where they are the owner + project_connections = ( + models.ProjectUsers.query.filter_by(user_id=current_user.username) + .filter_by(owner=1) + .all() + ) + + if not project_connections: + raise ddserr.RoleException( + message="You need to have the role 'Project Owner' in at least one project to be able to list any invites." + ) + # use set intersection to find overlaps between projects for invite and current_user + user_projects = set(entry.project.id for entry in project_connections) + user_projects_pubid = set(entry.project.public_id for entry in project_connections) + raw_invites = models.Invite.query.all() + hits = [] + for inv in raw_invites: + if inv.role == "Researcher" and set(proj.id for proj in inv.projects).intersection( + user_projects + ): + entry = row_to_dict(inv) + # do not list projects the current user does not own + entry["Projects"] = [ + project for project in entry["Projects"] if project in user_projects_pubid + ] + hits.append(entry) + else: + # in case further roles are defined in the future + raw_hits = [] + + return {"invites": hits, "keys": key_order} diff --git a/dds_web/database/models.py b/dds_web/database/models.py index 8569a21b8..15a7ccc1f 100644 --- a/dds_web/database/models.py +++ b/dds_web/database/models.py @@ -835,8 +835,11 @@ class Invite(db.Model): @property def projects(self): """Return list of project items.""" - - return [proj.project for proj in self.project_associations] + if self.project_invite_keys: + projects = [proj.project for proj in self.project_invite_keys] + else: + projects = [] + return projects def __str__(self): """Called by str(), creates representation of object""" diff --git a/dds_web/development/db_init.py b/dds_web/development/db_init.py index 22f8ba422..3595f935a 100644 --- a/dds_web/development/db_init.py +++ b/dds_web/development/db_init.py @@ -28,6 +28,9 @@ def fill_db(): """Fills the database with initial entries used for development.""" + maintenance_row = models.Maintenance.query.first() + maintenance_row.active = False + # Foreign key/relationship updates: # The model with the row db.relationship should append the row of the model with foreign key diff --git a/dds_web/errors.py b/dds_web/errors.py index 37bf4608f..ee82fedbf 100644 --- a/dds_web/errors.py +++ b/dds_web/errors.py @@ -423,3 +423,12 @@ def __init__( ): super().__init__(message) general_logger.warning(message) + + +class MaintenanceOngoingException(LoggedHTTPException): + + code = http.HTTPStatus.SERVICE_UNAVAILABLE + + def __init__(self, message="Maintenance of DDS is ongoing."): + """Inform that maintenance is ongoing.""" + super().__init__(message) diff --git a/dds_web/security/auth.py b/dds_web/security/auth.py index 039d1a0f8..579d31b10 100644 --- a/dds_web/security/auth.py +++ b/dds_web/security/auth.py @@ -77,6 +77,8 @@ def get_user_roles_common(user): has been specified, the user role is returned as Project Owner. Otherwise, it is Researcher. For all other users, return the value of the role set in the database table. + + Not run if the endpoint accepts all roles. """ if flask.request.path in "/api/v1/proj/create" and user.role not in [ "Unit Admin", diff --git a/dds_web/static/package-lock.json b/dds_web/static/package-lock.json index c30d40bcf..3dfaeb08a 100644 --- a/dds_web/static/package-lock.json +++ b/dds_web/static/package-lock.json @@ -478,9 +478,9 @@ "dev": true }, "node_modules/autoprefixer": { - "version": "10.4.11", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.11.tgz", - "integrity": "sha512-5lHp6DgRodxlBLSkzHOTcufWFflH1ewfy2hvFQyjrblBFlP/0Yh4O/Wrg4ow8WRlN3AAUFFLAQwX8hTptzqVHg==", + "version": "10.4.12", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.12.tgz", + "integrity": "sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q==", "dev": true, "funding": [ { @@ -493,8 +493,8 @@ } ], "dependencies": { - "browserslist": "^4.21.3", - "caniuse-lite": "^1.0.30001399", + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001407", "fraction.js": "^4.2.0", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", @@ -755,9 +755,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001400", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001400.tgz", - "integrity": "sha512-Mv659Hn65Z4LgZdJ7ge5JTVbE3rqbJaaXgW5LEI9/tOaXclfIZ8DW7D7FCWWWmWiiPS7AC48S8kf3DApSxQdgA==", + "version": "1.0.30001423", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001423.tgz", + "integrity": "sha512-09iwWGOlifvE1XuHokFMP7eR38a0JnajoyL3/i87c8ZjRWRrdKo1fqjNfugfBD0UDBIOz0U+jtNhJ0EPm1VleQ==", "dev": true, "funding": [ { @@ -864,14 +864,17 @@ } }, "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/color-convert": { @@ -1233,9 +1236,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.251", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.251.tgz", - "integrity": "sha512-k4o4cFrWPv4SoJGGAydd07GmlRVzmeDIJ6MaEChTUjk4Dmomn189tCicSzil2oyvbPoGgg2suwPDNWq4gWRhoQ==", + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", "dev": true }, "node_modules/emoji-regex": { @@ -1288,22 +1291,22 @@ } }, "node_modules/es-abstract": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.2.tgz", - "integrity": "sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.2", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", + "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", @@ -1313,6 +1316,7 @@ "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", "string.prototype.trimend": "^1.0.5", "string.prototype.trimstart": "^1.0.5", "unbox-primitive": "^1.0.2" @@ -2297,9 +2301,9 @@ } }, "node_modules/is-callable": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.6.tgz", - "integrity": "sha512-krO72EO2NptOGAX2KYyqbP9vYMlNAXdB53rq6f8LXY6RY7JdSR/3BD6wLUlPHSAesmY9vstNrjvqGaCiRK/91Q==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "engines": { "node": ">= 0.4" @@ -2309,9 +2313,9 @@ } }, "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -2874,10 +2878,13 @@ } }, "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/minimist-options": { "version": "4.1.0", @@ -3002,9 +3009,9 @@ "dev": true }, "node_modules/nan": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", - "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", "dev": true }, "node_modules/nanoid": { @@ -3142,16 +3149,15 @@ } }, "node_modules/nodemon": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.19.tgz", - "integrity": "sha512-4pv1f2bMDj0Eeg/MhGqxrtveeQ5/G/UVe9iO6uTZzjnRluSA4PVWf8CW99LUPwGB3eNIA7zUFoP77YuI7hOc0A==", + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", "dev": true, - "hasInstallScript": true, "dependencies": { "chokidar": "^3.5.2", "debug": "^3.2.7", "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", "semver": "^5.7.1", "simple-update-notifier": "^1.0.7", @@ -3701,9 +3707,9 @@ } }, "node_modules/postcss": { - "version": "8.4.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", - "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "version": "8.4.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", + "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", "dev": true, "funding": [ { @@ -4428,6 +4434,20 @@ } ] }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -4463,9 +4483,9 @@ } }, "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -4636,10 +4656,13 @@ } }, "node_modules/shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", - "dev": true + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.4.tgz", + "integrity": "sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/side-channel": { "version": "1.0.4", @@ -4722,9 +4745,9 @@ } }, "node_modules/socks": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", - "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", "dev": true, "dependencies": { "ip": "^2.0.0", @@ -5001,9 +5024,9 @@ "dev": true }, "node_modules/stylelint": { - "version": "14.11.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.11.0.tgz", - "integrity": "sha512-OTLjLPxpvGtojEfpESWM8Ir64Z01E89xsisaBMUP/ngOx1+4VG2DPRcUyCCiin9Rd3kPXPsh/uwHd9eqnvhsYA==", + "version": "14.14.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.14.0.tgz", + "integrity": "sha512-yUI+4xXfPHVnueYddSQ/e1GuEA/2wVhWQbGj16AmWLtQJtn28lVxfS4b0CsWyVRPgd3Auzi0NXOthIEUhtQmmA==", "dev": true, "dependencies": { "@csstools/selector-specificity": "^2.0.2", @@ -5012,7 +5035,7 @@ "cosmiconfig": "^7.0.1", "css-functions-list": "^3.1.0", "debug": "^4.3.4", - "fast-glob": "^3.2.11", + "fast-glob": "^3.2.12", "fastest-levenshtein": "^1.0.16", "file-entry-cache": "^6.0.1", "global-modules": "^2.0.0", @@ -5029,7 +5052,7 @@ "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.16", + "postcss": "^8.4.17", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^6.0.0", @@ -5039,7 +5062,7 @@ "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "style-search": "^0.1.0", - "supports-hyperlinks": "^2.2.0", + "supports-hyperlinks": "^2.3.0", "svg-tags": "^1.0.0", "table": "^6.8.0", "v8-compile-cache": "^2.3.0", @@ -5499,9 +5522,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "dev": true, "funding": [ { @@ -5720,12 +5743,12 @@ } }, "node_modules/yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", "dev": true, "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", @@ -6095,13 +6118,13 @@ "dev": true }, "autoprefixer": { - "version": "10.4.11", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.11.tgz", - "integrity": "sha512-5lHp6DgRodxlBLSkzHOTcufWFflH1ewfy2hvFQyjrblBFlP/0Yh4O/Wrg4ow8WRlN3AAUFFLAQwX8hTptzqVHg==", + "version": "10.4.12", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.12.tgz", + "integrity": "sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q==", "dev": true, "requires": { - "browserslist": "^4.21.3", - "caniuse-lite": "^1.0.30001399", + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001407", "fraction.js": "^4.2.0", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", @@ -6282,9 +6305,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001400", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001400.tgz", - "integrity": "sha512-Mv659Hn65Z4LgZdJ7ge5JTVbE3rqbJaaXgW5LEI9/tOaXclfIZ8DW7D7FCWWWmWiiPS7AC48S8kf3DApSxQdgA==", + "version": "1.0.30001423", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001423.tgz", + "integrity": "sha512-09iwWGOlifvE1XuHokFMP7eR38a0JnajoyL3/i87c8ZjRWRrdKo1fqjNfugfBD0UDBIOz0U+jtNhJ0EPm1VleQ==", "dev": true }, "caseless": { @@ -6349,13 +6372,13 @@ } }, "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "requires": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, @@ -6641,9 +6664,9 @@ } }, "electron-to-chromium": { - "version": "1.4.251", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.251.tgz", - "integrity": "sha512-k4o4cFrWPv4SoJGGAydd07GmlRVzmeDIJ6MaEChTUjk4Dmomn189tCicSzil2oyvbPoGgg2suwPDNWq4gWRhoQ==", + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", "dev": true }, "emoji-regex": { @@ -6693,22 +6716,22 @@ } }, "es-abstract": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.2.tgz", - "integrity": "sha512-XxXQuVNrySBNlEkTYJoDNFe5+s2yIOpzq80sUHEdPdQr0S5nTLz4ZPPPswNIpKseDDUS5yghX1gfLIHQZ1iNuQ==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.2", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", + "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", @@ -6718,6 +6741,7 @@ "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", "string.prototype.trimend": "^1.0.5", "string.prototype.trimstart": "^1.0.5", "unbox-primitive": "^1.0.2" @@ -7463,15 +7487,15 @@ } }, "is-callable": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.6.tgz", - "integrity": "sha512-krO72EO2NptOGAX2KYyqbP9vYMlNAXdB53rq6f8LXY6RY7JdSR/3BD6wLUlPHSAesmY9vstNrjvqGaCiRK/91Q==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true }, "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "requires": { "has": "^1.0.3" @@ -7895,9 +7919,9 @@ } }, "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", "dev": true }, "minimist-options": { @@ -7991,9 +8015,9 @@ "dev": true }, "nan": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", - "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", "dev": true }, "nanoid": { @@ -8102,15 +8126,15 @@ } }, "nodemon": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.19.tgz", - "integrity": "sha512-4pv1f2bMDj0Eeg/MhGqxrtveeQ5/G/UVe9iO6uTZzjnRluSA4PVWf8CW99LUPwGB3eNIA7zUFoP77YuI7hOc0A==", + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", "dev": true, "requires": { "chokidar": "^3.5.2", "debug": "^3.2.7", "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", "semver": "^5.7.1", "simple-update-notifier": "^1.0.7", @@ -8513,9 +8537,9 @@ "dev": true }, "postcss": { - "version": "8.4.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", - "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "version": "8.4.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", + "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", "dev": true, "requires": { "nanoid": "^3.3.4", @@ -9013,6 +9037,17 @@ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -9042,9 +9077,9 @@ } }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -9183,9 +9218,9 @@ "dev": true }, "shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.4.tgz", + "integrity": "sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==", "dev": true }, "side-channel": { @@ -9246,9 +9281,9 @@ "dev": true }, "socks": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", - "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", "dev": true, "requires": { "ip": "^2.0.0", @@ -9473,9 +9508,9 @@ "dev": true }, "stylelint": { - "version": "14.11.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.11.0.tgz", - "integrity": "sha512-OTLjLPxpvGtojEfpESWM8Ir64Z01E89xsisaBMUP/ngOx1+4VG2DPRcUyCCiin9Rd3kPXPsh/uwHd9eqnvhsYA==", + "version": "14.14.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.14.0.tgz", + "integrity": "sha512-yUI+4xXfPHVnueYddSQ/e1GuEA/2wVhWQbGj16AmWLtQJtn28lVxfS4b0CsWyVRPgd3Auzi0NXOthIEUhtQmmA==", "dev": true, "requires": { "@csstools/selector-specificity": "^2.0.2", @@ -9484,7 +9519,7 @@ "cosmiconfig": "^7.0.1", "css-functions-list": "^3.1.0", "debug": "^4.3.4", - "fast-glob": "^3.2.11", + "fast-glob": "^3.2.12", "fastest-levenshtein": "^1.0.16", "file-entry-cache": "^6.0.1", "global-modules": "^2.0.0", @@ -9501,7 +9536,7 @@ "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.16", + "postcss": "^8.4.17", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^6.0.0", @@ -9511,7 +9546,7 @@ "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "style-search": "^0.1.0", - "supports-hyperlinks": "^2.2.0", + "supports-hyperlinks": "^2.3.0", "svg-tags": "^1.0.0", "table": "^6.8.0", "v8-compile-cache": "^2.3.0", @@ -9870,9 +9905,9 @@ "dev": true }, "update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "dev": true, "requires": { "escalade": "^3.1.1", @@ -10037,12 +10072,12 @@ "dev": true }, "yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", "dev": true, "requires": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", diff --git a/dds_web/templates/404.html b/dds_web/templates/404.html index f66cf9bcf..0252f5a03 100644 --- a/dds_web/templates/404.html +++ b/dds_web/templates/404.html @@ -12,7 +12,7 @@

You can get back to the homepage here. - If in doubt, please get in touch with the SciLifeLab Data Centre. + If in doubt, please get in touch with the SciLifeLab Data Centre (datacentre@scilifelab.se).

{% endblock %} diff --git a/dds_web/templates/base.html b/dds_web/templates/base.html index 370901d76..9a1bf9820 100644 --- a/dds_web/templates/base.html +++ b/dds_web/templates/base.html @@ -51,6 +51,11 @@

Important Information