From 7e538cc24dfaeacae554910ae3d7a9ece9ec974a Mon Sep 17 00:00:00 2001 From: Jaimyn Mayer Date: Sun, 28 Jan 2024 09:31:20 +1000 Subject: [PATCH 01/17] remove unused decorators --- memberportal/membermatters/decorators.py | 70 ------------------------ 1 file changed, 70 deletions(-) delete mode 100644 memberportal/membermatters/decorators.py diff --git a/memberportal/membermatters/decorators.py b/memberportal/membermatters/decorators.py deleted file mode 100644 index 79f0b440..00000000 --- a/memberportal/membermatters/decorators.py +++ /dev/null @@ -1,70 +0,0 @@ -from django.http import HttpResponseForbidden, HttpResponse -from constance import config -import json - - -def login_required_401(function=None, redirect_field_name=None): - """ - Just make sure the user is authenticated to access a certain ajax view - - Found here: https://stackoverflow.com/questions/10031001/login-required-decorator-on-ajax-views-to-return-401-instead-of-302 - - Otherwise return a HttpResponse 401 - authentication required - instead of the 302 redirect of the original Django decorator - """ - - def _decorator(view_func): - def _wrapped_view(request, *args, **kwargs): - if request.user.is_authenticated: - return view_func(request, *args, **kwargs) - else: - return HttpResponse(status=401) - - return _wrapped_view - - if function is None: - return _decorator - else: - return _decorator(function) - - -def staff_required(view): - def wrap(request, *args, **kwargs): - if request.user.is_staff: - return view(request, *args, **kwargs) - else: - # if the user isn't authorised let them know - return HttpResponseForbidden() - - return wrap - - -def no_noobs(view): - def wrap(request, *args, **kwargs): - if request.user.profile.state == "noob": - # if the user isn't authorised let them know - return HttpResponseForbidden() - else: - return view(request, *args, **kwargs) - - return wrap - - -def api_auth(view): - def wrap(request, *args, **kwargs): - secret_key = config.API_SECRET_KEY - - if request.method == "GET" and request.GET.get("secret", "wrong") == secret_key: - return view(request, *args, **kwargs) - - elif request.method == "POST": - details = json.loads(request.body) - # if the secret key exists, and it matches the one we have stored - if details.get("secret") == secret_key: - print(True) - return view(request, *args, **kwargs) - - # if the user isn't authorised let them know - return HttpResponseForbidden("403 Access Forbidden") - - return wrap From 14b7186f22f741273b8ac210446fb9bea00955ca Mon Sep 17 00:00:00 2001 From: Jaimyn Mayer Date: Sun, 28 Jan 2024 09:36:07 +1000 Subject: [PATCH 02/17] tidied up redundant admin/staff user attributes --- memberportal/api_general/views.py | 23 +++++++++++------------ memberportal/profile/models.py | 3 +-- src-frontend/src/boot/routeGuards.ts | 2 +- src-frontend/src/layouts/MainLayout.vue | 3 +-- src-frontend/src/types/member.d.ts | 1 - 5 files changed, 14 insertions(+), 18 deletions(-) diff --git a/memberportal/api_general/views.py b/memberportal/api_general/views.py index 18525b57..ce195dcb 100644 --- a/memberportal/api_general/views.py +++ b/memberportal/api_general/views.py @@ -404,7 +404,7 @@ def get(self, request): else None, "subscriptionState": p.subscription_status, }, - "permissions": {"admin": user.is_admin}, + "permissions": {"staff": user.is_staff}, } return Response(response) @@ -491,7 +491,7 @@ class Kiosks(APIView): permission_classes = (permissions.AllowAny,) def get(self, request): - if not request.user.is_authenticated and not request.user.is_admin: + if not request.user.is_authenticated and not request.user.is_staff: return Response(status=status.HTTP_403_FORBIDDEN) kiosks = Kiosk.objects.all() @@ -520,7 +520,7 @@ def put(self, request, id=None): "HTTP_X_REAL_IP", request.META.get("REMOTE_ADDR") ) kiosk.checkin() - if not request.user.is_authenticated and not request.user.is_admin: + if not request.user.is_authenticated and not request.user.is_staff: return Response(status=status.HTTP_403_FORBIDDEN) else: kiosk = Kiosk.objects.get(kiosk_id=body.get("kioskId")) @@ -533,23 +533,22 @@ def put(self, request, id=None): play_theme=False, ) - if request.user.is_authenticated: - if request.user.is_admin: - if body.get("playTheme"): - kiosk.play_theme = body.get("playTheme") + if request.user.is_authenticated and request.user.is_staff: + if body.get("playTheme"): + kiosk.play_theme = body.get("playTheme") - if body.get("name"): - kiosk.name = body.get("name") + if body.get("name"): + kiosk.name = body.get("name") - if body.get("authorised") is not None and request.user.is_admin: - kiosk.authorised = body.get("authorised") + if body.get("authorised") is not None: + kiosk.authorised = body.get("authorised") kiosk.save() return Response() def delete(self, request, id): - if not request.user.is_authenticated and not request.user.is_admin: + if not request.user.is_authenticated and not request.user.is_staff: return Response(status=status.HTTP_403_FORBIDDEN) kiosk = Kiosk.objects.get(id=id) diff --git a/memberportal/profile/models.py b/memberportal/profile/models.py index e41624f1..653d85a1 100644 --- a/memberportal/profile/models.py +++ b/memberportal/profile/models.py @@ -167,7 +167,7 @@ class User(AbstractBaseUser, PermissionsMixin): password_reset_key = models.UUIDField(default=None, blank=True, null=True) password_reset_expire = models.DateTimeField(default=None, blank=True, null=True) staff = models.BooleanField(default=False) # an admin user for the portal - admin = models.BooleanField(default=False) # a superuser + admin = models.BooleanField(default=False) # a portal superuser USERNAME_FIELD = "email" REQUIRED_FIELDS = [] # Email & Password are required by default. @@ -521,7 +521,6 @@ def get_basic_profile(self): return { "id": self.user.id, "admin": self.user.is_staff, - "superuser": self.user.is_admin, "email": self.user.email, "excludeFromEmailExport": self.exclude_from_email_export, "registrationDate": self.created.strftime("%m/%d/%Y, %H:%M:%S"), diff --git a/src-frontend/src/boot/routeGuards.ts b/src-frontend/src/boot/routeGuards.ts index f1765a16..35a75203 100644 --- a/src-frontend/src/boot/routeGuards.ts +++ b/src-frontend/src/boot/routeGuards.ts @@ -40,7 +40,7 @@ export default boot(({ router, store }) => { // Check if the user must be an admin to access the route if (to.meta.admin === true) { - if (store.getters['profile/profile'].permissions.admin === true) + if (store.getters['profile/profile'].permissions.staff === true) return next(); else { return next({ name: 'Error403' }); diff --git a/src-frontend/src/layouts/MainLayout.vue b/src-frontend/src/layouts/MainLayout.vue index 56d0d7a4..49b51885 100644 --- a/src-frontend/src/layouts/MainLayout.vue +++ b/src-frontend/src/layouts/MainLayout.vue @@ -213,8 +213,7 @@ export default defineComponent({ if (this.$q.platform.is.electron && !link.kiosk) displayLink = false; if ( link.admin && - this.profile.permissions && - !this.profile.permissions.admin + this.profile?.permissions?.staff ) { displayLink = false; } diff --git a/src-frontend/src/types/member.d.ts b/src-frontend/src/types/member.d.ts index 24af19ca..83345146 100644 --- a/src-frontend/src/types/member.d.ts +++ b/src-frontend/src/types/member.d.ts @@ -21,7 +21,6 @@ export enum MemberSubscriptionState { interface MemberProfile { id: number; admin: boolean; - superuser: boolean; email: string; excludeFromEmailExport: boolean; registrationDate: string; From d83654ff4c4ea3848aa72dab4b6b50c6d5273fe8 Mon Sep 17 00:00:00 2001 From: Jaimyn Mayer Date: Sun, 28 Jan 2024 10:29:38 +1000 Subject: [PATCH 03/17] added membershipinfo scope to oidc --- .../membermatters/oidc_provider_settings.py | 48 ++++++++++++++++++- memberportal/membermatters/settings.py | 1 + 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/memberportal/membermatters/oidc_provider_settings.py b/memberportal/membermatters/oidc_provider_settings.py index b5dfaa03..f1f1419d 100644 --- a/memberportal/membermatters/oidc_provider_settings.py +++ b/memberportal/membermatters/oidc_provider_settings.py @@ -1,10 +1,56 @@ def userinfo(claims, user): # Populate claims dict. - claims["name"] = "{0} {1}".format(user.profile.first_name, user.profile.last_name) + claims["name"] = user.get_full_name() or "NO_NAME" claims["given_name"] = user.profile.first_name or "NO_FIRSTNAME" claims["family_name"] = user.profile.last_name or "NO_LASTNAME" claims["nickname"] = user.profile.screen_name or "NO_SCREENNAME" + claims["preferred_username"] = user.profile.screen_name or "NO_SCREENNAME" claims["email"] = user.email + claims["email_verified"] = user.email_verified claims["phone_number"] = user.profile.phone or "NO_PHONENUMBER" + claims["phone_number_verified"] = False + claims["updated_at"] = user.profile.modified.isoformat() return claims + + +from django.utils.translation import ugettext_lazy as _ +from oidc_provider.lib.claims import ScopeClaims + + +class CustomScopeClaims(ScopeClaims): + info_membershipinfo = ( + _("Membership Info"), + _( + "Current membership status, and other membership information like permissions/groups." + ), + ) + + def scope_membershipinfo(self): + groups = [] + state = self.user.profile.state + subscription_state = self.user.profile.subscription_state + subscriptionActive = subscription_state in ["active", "cancelling"] + firstSubscribed = self.user.profile.subscription_first_created + firstSubscribed = firstSubscribed.isoformat() if firstSubscribed else None + + if self.user.is_staff: + groups.append("staff") + + if self.user.is_admin: + groups.append("admin") + + if self.user.is_superuser: + groups.append("superuser") + + if self.user.profile.state == "active": + groups.append("active") + + return { + "state": state, + "active": state == "active", + "subscriptionState": subscription_state, + "subscriptionActive": subscriptionActive, + "firstSubscribedDate": firstSubscribed, + "groups": groups, + } diff --git a/memberportal/membermatters/settings.py b/memberportal/membermatters/settings.py index 607bddf8..01b8d13a 100644 --- a/memberportal/membermatters/settings.py +++ b/memberportal/membermatters/settings.py @@ -295,6 +295,7 @@ CONSTANCE_CONFIG_FIELDSETS = CONSTANCE_CONFIG_FIELDSETS OIDC_USERINFO = "membermatters.oidc_provider_settings.userinfo" +OIDC_EXTRA_SCOPE_CLAIMS = "membermatters.oidc_provider_settings.CustomScopeClaims" USE_X_FORWARDED_HOST = True SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") From 4d709a6719ec2598abf1997c59e2055a31aacd93 Mon Sep 17 00:00:00 2001 From: Jaimyn Mayer Date: Sun, 28 Jan 2024 10:29:55 +1000 Subject: [PATCH 04/17] removed old migration related function --- memberportal/profile/migrations/0001_initial.py | 1 - memberportal/profile/models.py | 7 ------- 2 files changed, 8 deletions(-) diff --git a/memberportal/profile/migrations/0001_initial.py b/memberportal/profile/migrations/0001_initial.py index 3b71603f..4ee1b0c6 100644 --- a/memberportal/profile/migrations/0001_initial.py +++ b/memberportal/profile/migrations/0001_initial.py @@ -264,7 +264,6 @@ class Migration(migrations.Migration): models.ImageField( blank=True, null=True, - upload_to=profile.models.Profile.path_and_rename, ), ), ( diff --git a/memberportal/profile/models.py b/memberportal/profile/models.py index 653d85a1..58b1e911 100644 --- a/memberportal/profile/models.py +++ b/memberportal/profile/models.py @@ -296,13 +296,6 @@ def reset_password(self): class Profile(models.Model): - def path_and_rename(self, filename): - ext = filename.split(".")[-1] - # set filename as random string - filename = f"profile_pics/{str(uuid.uuid4())}.{ext}" - # return the new path to the file - return os.path.join(filename) - STATES = ( ("noob", "Needs Induction"), ("active", "Active"), From 3288ec604acaf09dc7d0d7756a0c6c7ae7bbf6b9 Mon Sep 17 00:00:00 2001 From: Jaimyn Mayer Date: Sun, 28 Jan 2024 10:41:48 +1000 Subject: [PATCH 05/17] update black version and reformat --- memberportal/api_admin_tools/views.py | 8 +++++--- memberportal/api_general/views.py | 16 ++++++++-------- memberportal/membermatters/urls.py | 1 + memberportal/membermatters/wsgi.py | 1 + memberportal/profile/models.py | 26 +++++++++++++++----------- memberportal/requirements.txt | 2 +- package-lock.json | 4 ++-- 7 files changed, 33 insertions(+), 25 deletions(-) diff --git a/memberportal/api_admin_tools/views.py b/memberportal/api_admin_tools/views.py index b8547cc0..7cf61c45 100644 --- a/memberportal/api_admin_tools/views.py +++ b/memberportal/api_admin_tools/views.py @@ -726,9 +726,11 @@ def get(self, request, member_id): "totalTime": interlock_log.total_time, "totalCost": (interlock_log.total_cost or 0) / 100, "status": status, - "userEnded": interlock_log.user_ended.get_full_name() - if interlock_log.user_ended - else None, + "userEnded": ( + interlock_log.user_ended.get_full_name() + if interlock_log.user_ended + else None + ), } ) diff --git a/memberportal/api_general/views.py b/memberportal/api_general/views.py index ce195dcb..69a0a40b 100644 --- a/memberportal/api_general/views.py +++ b/memberportal/api_general/views.py @@ -394,14 +394,14 @@ def get(self, request): "expiry": p.stripe_card_expiry, }, }, - "membershipPlan": p.membership_plan.get_object() - if p.membership_plan - else None, - "membershipTier": p.membership_plan.member_tier.get_object() - if p.membership_plan - else None - if p.membership_plan - else None, + "membershipPlan": ( + p.membership_plan.get_object() if p.membership_plan else None + ), + "membershipTier": ( + p.membership_plan.member_tier.get_object() + if p.membership_plan + else None if p.membership_plan else None + ), "subscriptionState": p.subscription_status, }, "permissions": {"staff": user.is_staff}, diff --git a/memberportal/membermatters/urls.py b/memberportal/membermatters/urls.py index 2b9e0a20..3d933e30 100644 --- a/memberportal/membermatters/urls.py +++ b/memberportal/membermatters/urls.py @@ -1,5 +1,6 @@ """membermatters URL Configuration """ + import os import django.db.utils from django.contrib import admin diff --git a/memberportal/membermatters/wsgi.py b/memberportal/membermatters/wsgi.py index 603dcc85..bb9ef76f 100644 --- a/memberportal/membermatters/wsgi.py +++ b/memberportal/membermatters/wsgi.py @@ -3,6 +3,7 @@ For more information on this file, see https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ """ + import os from django.core.wsgi import get_wsgi_application import logging, sys diff --git a/memberportal/profile/models.py b/memberportal/profile/models.py index 58b1e911..d1850b7b 100644 --- a/memberportal/profile/models.py +++ b/memberportal/profile/models.py @@ -530,19 +530,23 @@ def get_basic_profile(self): "rfid": self.rfid, "memberBucks": { "balance": self.memberbucks_balance, - "lastPurchase": self.last_memberbucks_purchase.strftime( - "%m/%d/%Y, %H:%M:%S" - ) - if self.last_memberbucks_purchase - else None, + "lastPurchase": ( + self.last_memberbucks_purchase.strftime("%m/%d/%Y, %H:%M:%S") + if self.last_memberbucks_purchase + else None + ), }, "updateProfileRequired": self.must_update_profile, - "lastSeen": self.last_seen.strftime("%m/%d/%Y, %H:%M:%S") - if self.last_seen - else None, - "lastInduction": self.last_induction.strftime("%m/%d/%Y, %H:%M:%S") - if self.last_induction - else None, + "lastSeen": ( + self.last_seen.strftime("%m/%d/%Y, %H:%M:%S") + if self.last_seen + else None + ), + "lastInduction": ( + self.last_induction.strftime("%m/%d/%Y, %H:%M:%S") + if self.last_induction + else None + ), "stripe": { "cardExpiry": self.stripe_card_expiry, "last4": self.stripe_card_last_digits, diff --git a/memberportal/requirements.txt b/memberportal/requirements.txt index 55f40127..3655849d 100644 --- a/memberportal/requirements.txt +++ b/memberportal/requirements.txt @@ -5,7 +5,7 @@ humanize~=4.1.0 django-constance~=2.9.0 django-picklefield~=3.0.1 django-cors-headers~=3.12.0 -black==23.9.1 +black==24.1.0 pre-commit==2.19.0 djangorestframework~=3.13.1 djangorestframework-simplejwt>=4.7.2 diff --git a/package-lock.json b/package-lock.json index bc72371a..0fb1680f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "membermatters", - "version": "3.4.1", + "version": "3.6.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "membermatters", - "version": "3.4.1", + "version": "3.6.1", "devDependencies": { "eslint-webpack-plugin": "^3.1.1", "husky": "^6.0.0", From efb9f5d99f3e4feae27a9d35cc501eadfe7882fb Mon Sep 17 00:00:00 2001 From: Jaimyn Mayer Date: Sun, 28 Jan 2024 10:41:55 +1000 Subject: [PATCH 06/17] add pr docker build step --- .github/workflows/build_docker.pr.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_docker.pr.yml b/.github/workflows/build_docker.pr.yml index 489388b1..217a768c 100644 --- a/.github/workflows/build_docker.pr.yml +++ b/.github/workflows/build_docker.pr.yml @@ -18,10 +18,11 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Build Docker Image + - name: Build and push pr image id: docker_build uses: docker/build-push-action@v3 with: file: docker/Dockerfile platforms: linux/amd64 - push: false + push: true + tags: membermatters/membermatters:pr-${{github.ref_name}} From 87baaeb82480d7a38f74ef5e09f95118f9d1f360 Mon Sep 17 00:00:00 2001 From: Jaimyn Mayer Date: Sun, 28 Jan 2024 13:56:48 +1000 Subject: [PATCH 07/17] update gha --- .github/workflows/build_docker.pr.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build_docker.pr.yml b/.github/workflows/build_docker.pr.yml index 217a768c..cfb671f2 100644 --- a/.github/workflows/build_docker.pr.yml +++ b/.github/workflows/build_docker.pr.yml @@ -2,6 +2,7 @@ name: Build Docker Image (On PR) on: pull_request: + types: [opened, synchronize] branches: - "dev" From bb1880143e561cf57236f8b411b1af646da02dd6 Mon Sep 17 00:00:00 2001 From: Jaimyn Mayer Date: Sun, 28 Jan 2024 13:59:58 +1000 Subject: [PATCH 08/17] fix duplicate lint runs on PRs --- .github/workflows/black.yml | 2 +- .github/workflows/eslint.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index 7ea35942..ff1cdbaa 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -1,6 +1,6 @@ name: Python Linter (Black) -on: [push, pull_request] +on: [pull_request] jobs: lint-backend: diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml index 34dc5437..126f5102 100644 --- a/.github/workflows/eslint.yml +++ b/.github/workflows/eslint.yml @@ -1,5 +1,5 @@ name: JavaScript Linter (eslint) -on: [push, pull_request] +on: [pull_request] jobs: lint-frontend: runs-on: ubuntu-latest From 2a766b15014412c3c7751f1e7534bfbbfc54d0ca Mon Sep 17 00:00:00 2001 From: Jaimyn Mayer Date: Sun, 28 Jan 2024 14:14:25 +1000 Subject: [PATCH 09/17] fix docker build on pr --- .github/workflows/build_docker.pr.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_docker.pr.yml b/.github/workflows/build_docker.pr.yml index cfb671f2..9ff43005 100644 --- a/.github/workflows/build_docker.pr.yml +++ b/.github/workflows/build_docker.pr.yml @@ -19,6 +19,10 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Extract branch name + shell: bash + run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT + id: extract_branch - name: Build and push pr image id: docker_build uses: docker/build-push-action@v3 @@ -26,4 +30,4 @@ jobs: file: docker/Dockerfile platforms: linux/amd64 push: true - tags: membermatters/membermatters:pr-${{github.ref_name}} + tags: membermatters/membermatters:untrusted-pr-${{ steps.extract_branch.outputs.branch }} From f667460135aede7b207e34d9242b694ad94296ad Mon Sep 17 00:00:00 2001 From: Jaimyn Mayer Date: Sun, 28 Jan 2024 14:16:55 +1000 Subject: [PATCH 10/17] replace / in image name with - --- .github/workflows/build_docker.pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_docker.pr.yml b/.github/workflows/build_docker.pr.yml index 9ff43005..fd473e4d 100644 --- a/.github/workflows/build_docker.pr.yml +++ b/.github/workflows/build_docker.pr.yml @@ -21,7 +21,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Extract branch name shell: bash - run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT + run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" | tr / _ >> $GITHUB_OUTPUT id: extract_branch - name: Build and push pr image id: docker_build From 470a229a25222872cc35f4c99e50c249f81721cb Mon Sep 17 00:00:00 2001 From: Jaimyn Mayer Date: Sun, 28 Jan 2024 14:41:56 +1000 Subject: [PATCH 11/17] comment docker image name on pr --- .github/workflows/build_docker.pr.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_docker.pr.yml b/.github/workflows/build_docker.pr.yml index fd473e4d..3c9716f9 100644 --- a/.github/workflows/build_docker.pr.yml +++ b/.github/workflows/build_docker.pr.yml @@ -21,7 +21,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Extract branch name shell: bash - run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" | tr / _ >> $GITHUB_OUTPUT + run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" | tr / - >> $GITHUB_OUTPUT id: extract_branch - name: Build and push pr image id: docker_build @@ -31,3 +31,19 @@ jobs: platforms: linux/amd64 push: true tags: membermatters/membermatters:untrusted-pr-${{ steps.extract_branch.outputs.branch }} + + comment_docker_image: + needs: build-docker-pr + runs-on: ubuntu-latest + steps: + - name: Comment name of docker image + id: comment_docker_image + uses: actions/github-script@v6 + with: + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'Created image with name `membermatters/membermatters:untrusted-pr-${{ steps.extract_branch.outputs.branch }}`.' + }) From cdb77548656dbb7320397ddb3e2d66406334f25b Mon Sep 17 00:00:00 2001 From: Jaimyn Mayer Date: Sun, 28 Jan 2024 14:51:12 +1000 Subject: [PATCH 12/17] update gha comment --- .github/workflows/build_docker.pr.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_docker.pr.yml b/.github/workflows/build_docker.pr.yml index 3c9716f9..50557b3d 100644 --- a/.github/workflows/build_docker.pr.yml +++ b/.github/workflows/build_docker.pr.yml @@ -9,6 +9,8 @@ on: jobs: build-docker-pr: runs-on: ubuntu-latest + outputs: + branch: ${{ steps.extract_branch.outputs.branch }} steps: - name: Set up QEMU uses: docker/setup-qemu-action@v1 @@ -45,5 +47,5 @@ jobs: issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, - body: 'Created image with name `membermatters/membermatters:untrusted-pr-${{ steps.extract_branch.outputs.branch }}`.' + body: 'Created image with name `membermatters/membermatters:untrusted-pr-${{ needs.build-docker-pr.outputs.branch }}`.' }) From f7ee84b9f5b45c13368b0cc74f66c70f7998e97d Mon Sep 17 00:00:00 2001 From: Jaimyn Mayer Date: Sun, 28 Jan 2024 15:16:31 +1000 Subject: [PATCH 13/17] fixed typo in new oidc scope --- memberportal/membermatters/oidc_provider_settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/memberportal/membermatters/oidc_provider_settings.py b/memberportal/membermatters/oidc_provider_settings.py index f1f1419d..a7fd5da1 100644 --- a/memberportal/membermatters/oidc_provider_settings.py +++ b/memberportal/membermatters/oidc_provider_settings.py @@ -29,7 +29,7 @@ class CustomScopeClaims(ScopeClaims): def scope_membershipinfo(self): groups = [] state = self.user.profile.state - subscription_state = self.user.profile.subscription_state + subscription_state = self.user.profile.subscription_status subscriptionActive = subscription_state in ["active", "cancelling"] firstSubscribed = self.user.profile.subscription_first_created firstSubscribed = firstSubscribed.isoformat() if firstSubscribed else None From c47a0d75c230dd6954ec911345a1baeae4885156 Mon Sep 17 00:00:00 2001 From: Jaimyn Mayer Date: Sun, 28 Jan 2024 15:57:02 +1000 Subject: [PATCH 14/17] fix admin check display bug --- src-frontend/src/layouts/MainLayout.vue | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src-frontend/src/layouts/MainLayout.vue b/src-frontend/src/layouts/MainLayout.vue index 49b51885..e6c81f95 100644 --- a/src-frontend/src/layouts/MainLayout.vue +++ b/src-frontend/src/layouts/MainLayout.vue @@ -211,10 +211,7 @@ export default defineComponent({ if (link.memberOnly && this.profile.memberStatus !== 'Active') displayLink = false; if (this.$q.platform.is.electron && !link.kiosk) displayLink = false; - if ( - link.admin && - this.profile?.permissions?.staff - ) { + if (link.admin && !this.profile?.permissions?.staff) { displayLink = false; } From ee4e1a6a071a25baa021c011b1e8a4fdae49248b Mon Sep 17 00:00:00 2001 From: Rechner Fox <659028+rechner@users.noreply.github.com> Date: Thu, 1 Feb 2024 15:09:04 -0800 Subject: [PATCH 15/17] Update SpaceAPI to return integer version number --- memberportal/api_spacedirectory/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/memberportal/api_spacedirectory/views.py b/memberportal/api_spacedirectory/views.py index 3bb15975..71576587 100644 --- a/memberportal/api_spacedirectory/views.py +++ b/memberportal/api_spacedirectory/views.py @@ -103,7 +103,7 @@ def get(self, request): "open": config.SPACE_DIRECTORY_ICON_OPEN, "closed": config.SPACE_DIRECTORY_ICON_CLOSED, } - spaceapi["api_compatibility"] = ["0.14"] + spaceapi["api_compatibility"] = ["14"] ## Add the sensor data to the main body of the schema spaceapi["sensors"] = sensor_data From e194f2720ff8f21cf3088850001dc072103be530 Mon Sep 17 00:00:00 2001 From: Rechner Fox <659028+rechner@users.noreply.github.com> Date: Thu, 1 Feb 2024 15:25:42 -0800 Subject: [PATCH 16/17] Update pre-commit hook and re-format --- .pre-commit-config.yaml | 2 +- memberportal/api_admin_tools/views.py | 8 +++++--- memberportal/api_general/views.py | 16 ++++++++-------- memberportal/membermatters/urls.py | 1 + memberportal/membermatters/wsgi.py | 1 + memberportal/profile/models.py | 26 +++++++++++++++----------- 6 files changed, 31 insertions(+), 23 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 79ed3d1a..12e4e132 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/psf/black - rev: 21.8b0 + rev: 24.1.1 hooks: - id: black language_version: python3 diff --git a/memberportal/api_admin_tools/views.py b/memberportal/api_admin_tools/views.py index b8547cc0..7cf61c45 100644 --- a/memberportal/api_admin_tools/views.py +++ b/memberportal/api_admin_tools/views.py @@ -726,9 +726,11 @@ def get(self, request, member_id): "totalTime": interlock_log.total_time, "totalCost": (interlock_log.total_cost or 0) / 100, "status": status, - "userEnded": interlock_log.user_ended.get_full_name() - if interlock_log.user_ended - else None, + "userEnded": ( + interlock_log.user_ended.get_full_name() + if interlock_log.user_ended + else None + ), } ) diff --git a/memberportal/api_general/views.py b/memberportal/api_general/views.py index 18525b57..9b0c139a 100644 --- a/memberportal/api_general/views.py +++ b/memberportal/api_general/views.py @@ -394,14 +394,14 @@ def get(self, request): "expiry": p.stripe_card_expiry, }, }, - "membershipPlan": p.membership_plan.get_object() - if p.membership_plan - else None, - "membershipTier": p.membership_plan.member_tier.get_object() - if p.membership_plan - else None - if p.membership_plan - else None, + "membershipPlan": ( + p.membership_plan.get_object() if p.membership_plan else None + ), + "membershipTier": ( + p.membership_plan.member_tier.get_object() + if p.membership_plan + else None if p.membership_plan else None + ), "subscriptionState": p.subscription_status, }, "permissions": {"admin": user.is_admin}, diff --git a/memberportal/membermatters/urls.py b/memberportal/membermatters/urls.py index 2b9e0a20..3d933e30 100644 --- a/memberportal/membermatters/urls.py +++ b/memberportal/membermatters/urls.py @@ -1,5 +1,6 @@ """membermatters URL Configuration """ + import os import django.db.utils from django.contrib import admin diff --git a/memberportal/membermatters/wsgi.py b/memberportal/membermatters/wsgi.py index 603dcc85..bb9ef76f 100644 --- a/memberportal/membermatters/wsgi.py +++ b/memberportal/membermatters/wsgi.py @@ -3,6 +3,7 @@ For more information on this file, see https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ """ + import os from django.core.wsgi import get_wsgi_application import logging, sys diff --git a/memberportal/profile/models.py b/memberportal/profile/models.py index e41624f1..a02dadfb 100644 --- a/memberportal/profile/models.py +++ b/memberportal/profile/models.py @@ -538,19 +538,23 @@ def get_basic_profile(self): "rfid": self.rfid, "memberBucks": { "balance": self.memberbucks_balance, - "lastPurchase": self.last_memberbucks_purchase.strftime( - "%m/%d/%Y, %H:%M:%S" - ) - if self.last_memberbucks_purchase - else None, + "lastPurchase": ( + self.last_memberbucks_purchase.strftime("%m/%d/%Y, %H:%M:%S") + if self.last_memberbucks_purchase + else None + ), }, "updateProfileRequired": self.must_update_profile, - "lastSeen": self.last_seen.strftime("%m/%d/%Y, %H:%M:%S") - if self.last_seen - else None, - "lastInduction": self.last_induction.strftime("%m/%d/%Y, %H:%M:%S") - if self.last_induction - else None, + "lastSeen": ( + self.last_seen.strftime("%m/%d/%Y, %H:%M:%S") + if self.last_seen + else None + ), + "lastInduction": ( + self.last_induction.strftime("%m/%d/%Y, %H:%M:%S") + if self.last_induction + else None + ), "stripe": { "cardExpiry": self.stripe_card_expiry, "last4": self.stripe_card_last_digits, From ef62ee0bf07bb2c8ccf031220f69202b38d4f16c Mon Sep 17 00:00:00 2001 From: Jaimyn Mayer Date: Fri, 2 Feb 2024 14:59:13 +1000 Subject: [PATCH 17/17] v3.6.2 --- CHANGELOG.md | 26 +++++++++++++++++++++----- package.json | 2 +- src-frontend/package.json | 2 +- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f79a5707..3d33dbb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v3.6.2] - 2024-02-02 + +### Fixed + +- SpaceAPI return type for version number (thanks @rechner) + +### Added + +- New OIDC scope called `membershipinfo` and extra claims +- New GitHub Actions for checks and docker build on every PR + +### Changed + +- Cleaned up some old code/models +- Tidied up redundant staff/admin attributes + ## [v3.6.1] - 2024-01-20 ### Fixed @@ -543,11 +559,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - First run detection and fixture loading. - Added a handful of missing translation definitions. - Corner/border formatting with credit card component. -- https://github.com/membermatters/MemberMatters/issues/90 -- https://github.com/membermatters/MemberMatters/issues/91 -- https://github.com/membermatters/MemberMatters/issues/92 -- https://github.com/membermatters/MemberMatters/issues/93 -- https://github.com/membermatters/MemberMatters/issues/101 +- +- +- +- +- ## Versions prior to v2.1.0 don't have changelog entries diff --git a/package.json b/package.json index 42a694ca..52710f3c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "membermatters", - "version": "3.6.1", + "version": "3.6.2", "devDependencies": { "eslint-webpack-plugin": "^3.1.1", "husky": "^6.0.0", diff --git a/src-frontend/package.json b/src-frontend/package.json index 93fbcae2..53683727 100644 --- a/src-frontend/package.json +++ b/src-frontend/package.json @@ -1,6 +1,6 @@ { "name": "frontend", - "version": "3.6.1", + "version": "3.6.2", "description": "The MemberMatters frontend", "productName": "MemberMatters", "author": "Jaimyn Mayer ",