Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Organisation admin role #1126

Merged
merged 23 commits into from
Jan 23, 2024
Merged

Organisation admin role #1126

merged 23 commits into from
Jan 23, 2024

Conversation

nrjadkry
Copy link
Member

@nrjadkry nrjadkry commented Jan 22, 2024

What type of PR is this? (check all applicable)

  • πŸ• Feature
  • πŸ› Bug Fix
  • πŸ“ Documentation Update
  • 🎨 Style
  • πŸ§‘β€πŸ’» Code Refactor
  • πŸ”₯ Performance Improvements
  • βœ… Test
  • πŸ€– Build
  • πŸ” CI
  • πŸ“¦ Chore (Release)
  • ⏩ Revert

Describe this PR

This PR includes following features related to organisation admin:

  • An endpoint to add and remove organisation admin (can only be done by org admin)
  • Approval of organisation creation request ( can only be done by super admin)
    For this, a boolean field is added in the organisation table (approved). It will be false by default.
    Then, the admin can view the organisation list that are pending for approval. They will appear in the frontend only
    when they are approved.
  • Organisation list endpoint is updated. Admin can view the approved and unapproved organisations. Other users
    can only view the organisations that have been approved by admin
  • Endpoint to approve the organisation by admin

Todo

  • Add authentication in frontend for organisations list

Checklist before requesting a review

@nrjadkry
Copy link
Member Author

nrjadkry commented Jan 22, 2024

Tests have failed in this PR.
Looks like migration file is not accepted by github action. @spwoodcock
Also, I have a small query related to the roles function you have made,

async def super_admin(
    db: Session = Depends(get_db),
    user_data: AuthUser = Depends(login_required),
) -> AuthUser:
    """Super admin role, with access to all endpoints."""
    user_id = await get_uid(user_data)

    match = db.query(DbUser).filter_by(id=user_id, role=UserRole.ADMIN).first()

    if not match:
        log.error(f"User ID {user_id} requested an admin endpoint, but is not admin")
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN, detail="User must be an administrator"
        )
    return user_data

This is a function made to check if the user is a super_user or not, I guess it would be better if we return boolean value instead of returning exception. So, that we can use this function more effectively. What do you think @spwoodcock

@spwoodcock
Copy link
Member

spwoodcock commented Jan 22, 2024

Nice work!

Let's combine the migrations together from #1123

I will update this PR to include the extra fields.

The reason the tests fail if a migration is included, is because the backend ci image is cached with the old migrations.
The way to fix it is to delete the cache and allow it to rebuild: https://github.com/hotosm/fmtm/actions/caches
(the cache is image-cache-Linux for the development branch)

@spwoodcock
Copy link
Member

I merged the migrations files into one. Hope the workflow runs 🀞

@spwoodcock
Copy link
Member

spwoodcock commented Jan 22, 2024

Tests have failed in this PR. Looks like migration file is not accepted by github action. @spwoodcock Also, I have a small query related to the roles function you have made,

async def super_admin(
    db: Session = Depends(get_db),
    user_data: AuthUser = Depends(login_required),
) -> AuthUser:
    """Super admin role, with access to all endpoints."""
    user_id = await get_uid(user_data)

    match = db.query(DbUser).filter_by(id=user_id, role=UserRole.ADMIN).first()

    if not match:
        log.error(f"User ID {user_id} requested an admin endpoint, but is not admin")
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN, detail="User must be an administrator"
        )
    return user_data

This is a function made to check if the user is a super_user or not, I guess it would be better if we return boolean value instead of returning exception. So, that we can use this function more effectively. What do you think @spwoodcock

It's not just a function to determine if the user is admin, it's a dependency.
So this means it will return the object that we want to use, in this case the user object:
user = Depends(super_admin)

This will either return a user if they are admin, or throw an error if they are not.

Doing it this way prevents an extra layer of logic:

is_admin = super_admin(user_id)
if is_admin:
    do_stuff_if_admin

do_stuff_if_not_admin

@spwoodcock
Copy link
Member

A couple of things of note:

  • Please reset your branch to the latest, to prevent conflicts from the organisation file names: organization_routes --> organisation_routes
    git fetch origin/feat-user-roles
    git reset --hard origin/feat-user-roles
  • See my comment above about usage of Depends.
  • Please try to use the British English spelling of organisation going forward, for consistency in the code (this was done in PR Pedantic renaming for consistency with databaseΒ #1114 to avoid conflicts with the already existing database).

@spwoodcock
Copy link
Member

The org_admin and super_admin endpoints are special cases, as they use different tables:

  • org_admin uses organisation_managers table.
  • super_admin uses user.role field.

For all other roles, they are in the user_role table, so we can do an easy hierarchy of roles to determine if the user has permission.
E.g. using > operators to determine that if the MAPPER role is required, then any role > ProjectRoles.MAPPER are accepted.

@spwoodcock
Copy link
Member

I see the issue you were facing:

  • In most cases endpoints are assessing the role based on the user that called them.
  • In some cases, we need to determine the role of a different user id (e.g. admin endpoint to add a user as organisation admin).

In some cases I separated out the logic from the dependency (used via Depends) and the logic (which can be called separately, outside of Depends).

@spwoodcock spwoodcock merged commit 36ae5d4 into development Jan 23, 2024
6 checks passed
@spwoodcock spwoodcock deleted the feat-user-roles branch January 23, 2024 14:08
spwoodcock added a commit that referenced this pull request Jan 25, 2024
* build: remove ref to script_domain (move to separate repo)

* docs: add CNAME for custom docs domain

* build: move install.sh to fmtm-installer repo

* ci: remove install script from pr labeller

* docs: update info for using easy install script

* build: add justfile to repo for basic commands (#1098)

* build: add justfile to repo for basic commands

* build: remove Makefile, update Justfile

* build: add Justfile commands to clean databases

* docs: add Justfile to pr auto labeller

* refactor: organization routes/crud/schemas to use best practice (#1096)

* fix: use enums for HTTPStatus over codes

* refactor: update organization routes/crud/schemas best pracice

* added int to the union with str in org_exists functions

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: Niraj Adhikari <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* feat: add basic user role support to backend (#1094)

* feat: update role enums: UserRole and ProjectRole

* feat: update DbUserRole model to use ProjectRole enum + comp key

* build: update base schema with new enum types

* fix: osm login methods to async

* feat: add basic roles: super admin & validator

* build: add migration for ProjectRole db enum type

* build: fix migrations with revert for projectrole

* build: fix enum migrations with intermediate varchar

* fix: handle invalid access tokens

* refactor: correct use of 403 http status over 401

* refactor: tidy minor code edits & lint fixes

* build: default to 4 workers on dev uvicorn container

* feat: add project_deps with get_project_by_id logic

* feat: add org_admin role to role deps

* fix: add user role to response /me for frontend

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* refactor: fix all pre-commit.ci linting errors (#1101)

* build: add migration for ProjectRole db enum type

* fix: database model backrefs for DbUserRole --> (DbProject/DbUser)

* fix: add debug user to bypass auth during tests

* refactor: simplify project deletion endpoint /project/{id}

* test: add test for project deletion endpoint

* refactor: rename upload_multi_polygon --> custom_task_boundaries

* ci: disable markdownlint rule MD033 (allow inline html img resize)

* docs: update docs home page to use ref links

* refactor: fix all linting errors for code

* ci: add CONTRIBUTING.md to prettier ignore list

* docs: fix linting errors for all markdown docs

* refactor: rename LICENSE --> LICENSE.md

* refactor: update badges in readme

* docs: add allcontributors to badge table

* ci: add LICENSE.md to markdownlint ignore

* ci: update markdownlint ignore syntax for ci

* ci: add LICENSE.md to prettier ignore

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* style: revert prettier changes to LICENSE.md

* ci: update pre-commit hook versions

* docs: fix markdown linting errors after update

* ci: disable hadolint until bundled binary

* ci: do not run shellcheck on contrib dir

* ci: ignore SC2188,SC2143 from shellcheck

* refactor: fix lint errors for all shell/bash scripts

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* fix: editable vector layer in ol for project creation (#1102)

* fix: backend import error fix

* fix (vectorLayer): style - conditionaly apply style on onModify present

* fix (splitTasks): map - edit added to splitted taskLayer

* fix (splitTasks): onModify - edited geojson set to dividedTaskGeojson state

* feat (createNewProject): only enable generate task btn if fgb file fetch is completed

* fix (createNewProject): splitTasks - logic fix

* fix (createNewProject): splitTasks - clear dividedTaskGeojson, splitTasksSelection, and dataExtractGeojson state on previous click

* feat (createNewProject): splitTasks - show loader and message until FGB file is fetching

* fix (createNewProject): taskSplit - display error on taskSplit fail

* fix vectorLayer: on modifyEnd return area of boundary as well

* fix button: loading text added to the button

* fix NewDefineAreaMap: removed data extraction in progress message from mapComponent

* fix (createNewProject): splitTasks - clearing state on step toggle remove

* fix (createNewProject): uploadArea - clear step4 & step5 step on AOI edit

* fix (createNewProject): dataExtract - generateTaskBTN added, disable next until taskGeneration success, state logic changed to track extractWays & featureType state validation

* fix (createNewProject): dataExtract - clear file state on reset click or if generateDataExtract click

* fix (createNewProject): customLine, customPolygon file state clear on AOI edit

* fix (createNewProject): dataExtract - clear previous extractGeojson, customLine, customPolygon on generate extract, btn disable state update

* fix: limit project area during create (#1109)

* fix: backend import error fix

* fix (vectorLayer): style - conditionaly apply style on onModify present

* fix (splitTasks): map - edit added to splitted taskLayer

* fix (splitTasks): onModify - edited geojson set to dividedTaskGeojson state

* feat (createNewProject): only enable generate task btn if fgb file fetch is completed

* fix (createNewProject): splitTasks - logic fix

* fix (createNewProject): splitTasks - clear dividedTaskGeojson, splitTasksSelection, and dataExtractGeojson state on previous click

* feat (createNewProject): splitTasks - show loader and message until FGB file is fetching

* fix (createNewProject): taskSplit - display error on taskSplit fail

* fix vectorLayer: on modifyEnd return area of boundary as well

* fix button: loading text added to the button

* fix NewDefineAreaMap: removed data extraction in progress message from mapComponent

* fix (createNewProject): splitTasks - clearing state on step toggle remove

* fix (createNewProject): uploadArea - clear step4 & step5 step on AOI edit

* fix (createNewProject): dataExtract - generateTaskBTN added, disable next until taskGeneration success, state logic changed to track extractWays & featureType state validation

* fix (createNewProject): dataExtract - clear file state on reset click or if generateDataExtract click

* fix (createNewProject): customLine, customPolygon file state clear on AOI edit

* fix (createNewProject): dataExtract - clear previous extractGeojson, customLine, customPolygon on generate extract, btn disable state update

* fix (createNewProject): uploadArea - warning & error shown if AOI exceeds 100 & 1000 sq.km respectively

* fix: use organization_manager table for org admins

* fix (newProjectDetails): searchInput - width increased (#1111)

* fix (frontend): projection validity check using coordinates of extent (#1112)

* docs: link to docs.hotosm.org for versioning info

* refactor: remove variable from docker install script

* ci: add py310 version to black code formatter

* docs: add link to pre-commit info in docs

* refactor: renaming for consistency with database (#1114)

* docs: update info about interactive api debugging port

* docs: add timestamp to doc pages via plugin

* build: add git-revision-date-localized plugin to docs group

* ci: docs build use image from gh-workflows

* build: upgrade osm-fieldwork-->0.4.1, osm-rawdata-->0.2.6

* Fix condition in elif statement for Feature type detection

* docs: update markdown links from inline to reference (footnote) style (#1116)

* Clean up links in contributing

* done: CONTRIBUTING.md

* done: INSTALL.md

* done: User-Mantual-For-Project-Managers.md

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Moving script file to a new directory

* move new script file to a new directory

* deleted superfluous XINSTALL copy.md

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

* refactor: fix linting errors in project_crud

* feat: paginated submissions by project (#1110)

* feat: submission form fields for the submision table

* feat: paginated submissions by project

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* refactor: format submission_routes, remove dup import

* refactor: fix incorrect import from app.submission

* run pre-commit

---------

Co-authored-by: sujanadh <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: spwoodcock <[email protected]>

* fix: tile archive download for projects

* refactor: refactor odk appuser + qrcode function naming

* refactor: add metadata_username to odk qr code as test

* docs: use code of conduct on docs.hotosm.org

* fix divide by square on multipolygon geojson

* build: upgrade fmtm-splitter v0.2.6 --> v1.0.0rc0 (#1122)

* feat: add test coverage metric (#1129)

* build: add coverage.py to test dependencies

* docs: add dev info about coverage and profiling

* refactor: add doxygen output to gitignore

* build: add coverage-badge to test deps

* ci: update all workflows v1.4.2 --> v1.4.3

* ci: add coverage output during deploy pytest

* docs: add coverage stats to readme

* build: lock dependencies after merge coverage+fmtm-splitter

* build: add coverage files to gitignore

* ci: update pytest workflow test to use coverage

* ci: update all workflows v1.4.3 --> v1.4.4

* docs: add coverage link to docs page sidebar

* hotfix: geom type not populated with feature type

* ci: add simple smoke test to frontend deploy

* feat: organisation approval and admin endpoints (#1126)

* dependencies to cehck if user_exists

* endpoint to add organisation admin

* added approved field in organisation model

* fix: table name in migration file for organisations

* feat: organisations list api updated according to role

* feat: endpoint to approve organisations

* update: get organisation endpoint for filtering approval

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* added docstrings

* fix: pre-commit linting errors

* added docstring in user_deps file

* build: add default odk credentials to organisations

* build: merge migrations to organisations table

* refactor: fix linting errors

* refactor: remove subscription_tier field for orgs

* build: add public.organisation.approved field to base schema

* refactor: remove extra url field from DbOrganisation

* refactor: fix organizationModel dir --> organisation for import

* fix: remove router get_db global dependency (on routes)

* fix: use separate super_admin + check_super_admin deps

* fix: update org_admin to also allow super_admin

* refactor: remove missed log.warning from organisations endpoint

* fix: separate Depends from logic, working org approval

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: spwoodcock <[email protected]>

* ci: fix frontend smoke test with .env file

* refactor: update project dashboard to use deps functions (#1127)

* Refactor: updated code to use deps function

* Created new deps function org_from_project

* fix: call check_org_exists logic from dependency

* refactor: var naming for consistency

---------

Co-authored-by: sujanadh <[email protected]>
Co-authored-by: spwoodcock <[email protected]>

* feat: paginated submissions per task (#1128)

* merge development

* feat: paginated submissions by task

---------

Co-authored-by: sujanadh <[email protected]>

* fix: Depends usage for task_submissions endpoint

* build: replace project.private field with project.visibility enum (#1132)

* build: remove project_allowed_users table from db

* build: remove odk_central_src field from project table

* refactor: tidy/reorder project db model fields

* build: remove project.task_creation_mode field + enum

* build: replace project.private field with project.visibility enum

* fix: fix visibility migration column add syntax

* fix: apply migration to projects table

* build: fix check for projectvisibility type in migration

* ci: update workflows 1.4.5 for mkdocs --dirty

* ci: add sleep 5 for frontend smoke test dev startup

* ci: replace black with ruff-format

* build: update docker install script to handle root user

* docs: add info about using pyright for type checking

* ci: add tool.pyright config section to pyproject.toml

* fix: use optional params for extra AuthUser items

* refactor: fix return type for organisation url validator

* feat: added withcredential to include cookies on organization list api

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* build: add deployment container replicas and resource constraints (#1139)

* build: update backend image to use 1 uvicorn worker

* build: add api deploy replicas, remove container_name

* build: default to 1 local replica for easier debug

* docs: update container name for docker logs cmd

* fix: return of AuthUser during debug tests + linting

* feat: endpoint to return count of validated and mapped tasks (#1138)

* feat: new endpoint to return count of validated and mapped task

* refactor: move to tasks router + use pydantic model

* refactor: rename task_activity route --> tasks/activity

---------

Co-authored-by: sujanadh <[email protected]>
Co-authored-by: spwoodcock <[email protected]>

* feat: add AOI editing to map during project creation (#1135)

* feat (createNewProject): mapControlComponent - mapControlComponent including edit, undo added

* feat AssetModules: icons added

* feat (createNewProject): splitTasks - edit task on editBtn click

* fix codeRefactor: consoles removed

* fix mapControlComponent: undoIcon removed

* refactor(frontend): use absolute (aliased) imports over relative imports (#1136)

* fix: add vite alias @ for src dir

* refactor(frontend): replace all relative imports with @ alias

* build: add lint command to package.json (eslint)

* build: add @ alias to tsconfig for type imports

* refactor: fix all linting errors from eslint

* fix: browser console errors incorrect React usage

* fix: add axios interceptor withCredentials, plus API const

* refactor: fix remaining relative imports

* refactor: remove withCredentials from org endpoint (use interceptor)

---------

Co-authored-by: Niraj Adhikari <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Nishit Suwal <[email protected]>
Co-authored-by: Niraj Adhikari <[email protected]>
Co-authored-by: sujanadh <[email protected]>
Co-authored-by: JC CorMan <[email protected]>
Co-authored-by: Sujan Adhikari <[email protected]>
Co-authored-by: Deepak Pradhan <[email protected]>
Co-authored-by: Deepak Pradhan (Varun) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend Related to backend code frontend Related to frontend code migration Contains a DB migration
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants