Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .github/actions/setup-python/action.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: 'Setup Python'
description: 'Prints a greeting message'
description: 'Sets up Python, uv, and installs backend dependencies'
inputs:
python-version:
required: true
Expand All @@ -16,7 +16,8 @@ runs:
with:
python-version: ${{ inputs.python-version }}
enable-cache: true
cache-dependency-path: ./uv.lock
- name: Install visitran-cloud dependencies
cache-dependency-path: backend/uv.lock
- name: Install backend dependencies
shell: bash
run: uv sync
working-directory: backend
run: uv sync --group test
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@

## Checklist

I have read and understood the [Contribution Guidelines]().
I have read and understood the [Contribution Guidelines]().
130 changes: 64 additions & 66 deletions .github/workflows/core-backend-tests.yaml
Original file line number Diff line number Diff line change
@@ -1,73 +1,71 @@
---
name: Minimal Tests

on:
workflow_dispatch:
push:
branches: ["main"]
pull_request:
branches: ["main"]

concurrency:
group: ${{ github.repository }}-${{ github.head_ref || github.sha }}-${{ github.workflow }}
cancel-in-progress: true

env:
FORCE_COLOR: "1"

jobs:
minimal_tests:
name: Minimal Tests
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
python-version: ["3.10"]
defaults:
run:
working-directory: backend
steps:
- uses: actions/checkout@v4
with:
lfs: true

- name: Setup Python
uses: ./.github/actions/setup-python/
with:
python-version: ${{ matrix.python-version }}

on:
workflow_dispatch:
push:
branches: ["main"]
pull_request:
branches: [ "main"]
# pre-commit checks handled by pre-commit.ci

concurrency:
group: ${{ github.repository }}-${{ github.head_ref || github.sha }}-${{ github.workflow }}
cancel-in-progress: true
env:
FORCE_COLOR: "1"
jobs:
minimal_tests:
name: Minimal Tests
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
python-version: ["3.11"] #,"3.9","3.10"]
steps:
#----------------------------------------------
# check-out repo and set-up python
#----------------------------------------------
- uses: actions/checkout@v4
with:
lfs: true
- name: Setup Python
uses: ./.github/actions/setup-python/
with:
python-version: ${{ matrix.python-version }}
- name: Cache pre-commit hooks
uses: actions/cache@v4
if: github.ref != 'refs/heads/main'
with:
path: ~/.cache/pre-commit
key: ${{ runner.os }}-pre-commit-${{ hashFiles('.pre-commit-config.yaml') }}
- name: Run tests
env:
DJANGO_SETTINGS_MODULE: backend.server.settings.dev
run: |
uv run coverage run --rcfile=pyproject.toml --source=. -m \
pytest -x -vv ../tests/unit \
--ignore=../tests/unit/test_logs.py \
--ignore=../tests/unit/test_visitran_adapters \
--ignore=../tests/unit/test_visitran_backend \
-m "not snowflake and not bigquery and not trino and not postgres"

- name: Check pre-commit
if: github.ref != 'refs/heads/main'
run: |
uv run pre-commit run --all-files
- name: Run minimal core tests
run: |
uv run coverage run --rcfile=pyproject.toml --data-file=minimal.cov --context="minimal" --source=. -m \
pytest -x -vv -m "not snowflake and not bigquery and not trino and not postgres"
- name: Run backend tests
run: |
uv run coverage run --rcfile=pyproject.toml --data-file=backend.cov --context="backend" --source=. -m \
pytest -x -vv ./visitran_backend
- name: Generate coverage report
run: |
uv run coverage report -m
uv run coverage xml
Comment thread
greptile-apps[bot] marked this conversation as resolved.

- name: Combine to coverage xml
run: |
uv run coverage combine backend.cov minimal.cov
uv run coverage report -m
uv run coverage xml
- name: Git fetch unshallow
run: |
git fetch --unshallow
- name: Git fetch unshallow
working-directory: .
run: git fetch --unshallow

- name: Core SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
if: ${{ github.actor != 'dependabot[bot]' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
projectBaseDir: ./
args: >
-Dproject.settings=./sonar-project.properties
- name: SonarCloud Scan
uses: SonarSource/sonarcloud-github-action@master
if: ${{ github.actor != 'dependabot[bot]' }}
continue-on-error: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
projectBaseDir: ./
args: >
-Dproject.settings=./sonar-project.properties
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,4 @@ backend/backend/utils/load_models/yaml_models.yaml

# macOS
.DS_Store
**/.DS_Store
**/.DS_Store
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ repos:
- id: markdownlint
args: ["--config", "markdownlint.yaml"]
- repo: https://github.com/pycqa/docformatter
rev: v1.7.5
rev: v1.7.7
hooks:
- id: docformatter
- repo: https://github.com/adrienverge/yamllint
Expand Down
2 changes: 1 addition & 1 deletion backend/backend/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from dotenv import load_dotenv

from .celery import app as celery_app
from backend.backend.celery import app as celery_app

load_dotenv()
__all__ = ["celery_app"]
22 changes: 12 additions & 10 deletions backend/backend/account/authentication_controller.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Authentication controller that delegates to plugin or OSS service.

Uses the same interface as ScalekitService for compatibility.
If an authentication plugin is available (cloud), it uses the plugin.
Uses the same interface as ScalekitService for compatibility. If an
authentication plugin is available (cloud), it uses the plugin.
Otherwise, it falls back to the default AuthenticationService (OSS).
"""

Expand Down Expand Up @@ -179,8 +179,9 @@ def invite_user(
) -> list:
"""Invite user(s) to organization.

Accepts either a user_list (from the view) or a single email+role.
Returns a list of {email, status, message} dicts for failed invites.
Accepts either a user_list (from the view) or a single
email+role. Returns a list of {email, status, message} dicts for
failed invites.
"""
if user_list is None and email:
user_list = [{"email": email, "role": role}]
Expand All @@ -207,8 +208,9 @@ def remove_users_from_organization(
) -> list:
"""Remove users from organization by email.

Looks up users by email, deletes their OrganizationMember records,
and delegates to auth service for any cloud-specific cleanup.
Looks up users by email, deletes their OrganizationMember
records, and delegates to auth service for any cloud-specific
cleanup.

Returns a list of failed removals.
"""
Expand Down Expand Up @@ -397,8 +399,8 @@ def delete_user_invitation(
def _resolve_role_name(role: str) -> str:
"""Resolve a role_id to its role name if needed.

If 'role' is already a name (e.g. 'admin'), return as-is.
If 'role' is a role_id (e.g. 'rol_123'), look up the Roles table.
If 'role' is already a name (e.g. 'admin'), return as-is. If
'role' is a role_id (e.g. 'rol_123'), look up the Roles table.
"""
try:
from pluggable_apps.user_access_control.models.roles import Roles
Expand All @@ -414,8 +416,8 @@ def add_user_role(
) -> Optional[dict]:
"""Change a user's role in an organization.

Looks up the user by email, updates the OrganizationMember record,
and delegates to Scalekit if available.
Looks up the user by email, updates the OrganizationMember
record, and delegates to Scalekit if available.
"""
from backend.core.models.organization_member import OrganizationMember
from django.contrib.auth import get_user_model
Expand Down
52 changes: 40 additions & 12 deletions backend/backend/account/authentication_service.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""Authentication service for OSS mode.

Follows the same interface as ScalekitService to ensure compatibility.
Handles user signup, login, logout, and session management using Django's
built-in authentication system.
Handles user signup, login, logout, and session management using
Django's built-in authentication system.
"""

import logging
Expand Down Expand Up @@ -41,7 +41,8 @@ class AuthenticationService:
"""Authentication service for OSS mode.

Implements the same interface as ScalekitService for compatibility.
Provides signup, login, logout, and session management using Django sessions.
Provides signup, login, logout, and session management using Django
sessions.
"""

def __init__(self) -> None:
Expand Down Expand Up @@ -338,13 +339,19 @@ def get_roles(self) -> list:
def add_organization_user_role(
self, organization_id: str, user: Any, user_role_name: str
) -> Optional[list]:
"""Add role to user. OSS stub."""
"""Add role to user.

OSS stub.
"""
return None # Not supported in OSS

def assign_role_to_org_user(
self, organization_id: str, user: Any, user_role_name: str = "admin"
) -> list:
"""Assign role to organization user. OSS stub."""
"""Assign role to organization user.

OSS stub.
"""
return [] # Not supported in OSS

def get_organization_role_of_user(
Expand All @@ -360,13 +367,19 @@ def get_organization_role_of_user(
def invite_user(
self, admin: Any, org_id: str, email: str, role: str = "admin"
) -> bool:
"""Invite a user to organization. OSS stub."""
"""Invite a user to organization.

OSS stub.
"""
return False # Not supported in OSS

def remove_users_from_organization(
self, admin: Any, organization_id: str, user_emails: list
) -> list:
"""Remove users from organization. OSS stub."""
"""Remove users from organization.

OSS stub.
"""
return [] # Not supported in OSS

def get_organizations_users(self, org_id: str) -> list:
Expand All @@ -380,11 +393,17 @@ def get_organizations_users(self, org_id: str) -> list:
]

def get_invitations(self, organization_id: str) -> list:
"""Get pending invitations. OSS returns empty."""
"""Get pending invitations.

OSS returns empty.
"""
return []

def delete_invitation(self, organization_id: str, invitation_id: str) -> bool:
"""Delete invitation. OSS stub."""
"""Delete invitation.

OSS stub.
"""
return False

# =========================================================================
Expand Down Expand Up @@ -418,11 +437,17 @@ def get_organizations_by_user_id(self, user_id: str) -> list:
]

def create_roles(self, role: Any) -> Any:
"""Create role. OSS stub."""
"""Create role.

OSS stub.
"""
return None

def delete_role(self, role_id: str) -> bool:
"""Delete role. OSS stub."""
"""Delete role.

OSS stub.
"""
return False

def forgot_password(self, request: HttpRequest) -> Response:
Expand Down Expand Up @@ -550,7 +575,10 @@ def validate_reset_token(self, request: HttpRequest) -> Response:
)

def reset_user_password(self, user: Any) -> Response:
"""Reset user password. OSS stub (legacy interface)."""
"""Reset user password.

OSS stub (legacy interface).
"""
return Response(
status=status.HTTP_400_BAD_REQUEST,
data={"error": "Password reset not supported in OSS mode."},
Expand Down
4 changes: 2 additions & 2 deletions backend/backend/account/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
class DefaultOrg:
"""Default organization constants.

Used for OSS mode when auto-creating a personal organization.
Legacy mock user support retained for backward compatibility.
Used for OSS mode when auto-creating a personal organization. Legacy
mock user support retained for backward compatibility.
"""
# Legacy mock user support (for backward compatibility with env-based auth)
ORGANIZATION_NAME = "default_org"
Expand Down
3 changes: 2 additions & 1 deletion backend/backend/account/dto.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Data transfer objects for account module.

These DTOs provide a common interface for both OSS and cloud authentication.
These DTOs provide a common interface for both OSS and cloud
authentication.
"""

from dataclasses import dataclass
Expand Down
Loading
Loading