Skip to content

Commit

Permalink
Merge pull request #452 from MTES-MCT/master
Browse files Browse the repository at this point in the history
Release 6/11/2024
  • Loading branch information
tristan-gueguen authored Nov 6, 2024
2 parents cf65e90 + 03f7946 commit e2e8fd7
Show file tree
Hide file tree
Showing 11 changed files with 427 additions and 261 deletions.
10 changes: 8 additions & 2 deletions app/controllers/authentication.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import graphene
from flask import after_this_request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity

from flask_jwt_extended import (
jwt_required,
get_jwt_identity,
current_user as current_actor,
)
from app import app, db
from app.controllers.utils import Void
from app.domain.user import (
Expand Down Expand Up @@ -124,6 +127,9 @@ def mutate(cls, _, info):
@jwt_required(refresh=True)
def rest_refresh_token():
try:
if not current_actor:
raise AuthenticationError("Current user not found")

identity = get_jwt_identity()
if identity and identity.get("controller"):
tokens = refresh_controller_token()
Expand Down
12 changes: 8 additions & 4 deletions app/domain/regulation_computations.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ def get_regulatory_alerts(user_id, start_date=None, end_date=None):


def get_regulatory_computations(user_id, start_date=None, end_date=None):
return RegulationComputation.query.filter(
RegulationComputation.user_id == user_id,
RegulationComputation.day.between(start_date, end_date),
).all()
return (
RegulationComputation.query.filter(
RegulationComputation.user_id == user_id,
RegulationComputation.day.between(start_date, end_date),
)
.order_by(RegulationComputation.creation_time)
.all()
)
1 change: 0 additions & 1 deletion app/helpers/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,6 @@ def logout():
db.session.commit()


@jwt_required(refresh=True)
def delete_refresh_token():
from app.models.refresh_token import RefreshToken
from app.models.controller_refresh_token import ControllerRefreshToken
Expand Down
6 changes: 4 additions & 2 deletions app/helpers/authentication_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ def wrap_jwt_errors(f):
def wrapper(*args, **kwargs):
try:
return f(*args, **kwargs)
except (NoAuthorizationError, InvalidHeaderError):
except (NoAuthorizationError, InvalidHeaderError) as e:
app.logger.info(f"Authorization error: {str(e)}")
raise AuthenticationError(
"Unable to find a valid cookie or authorization header"
)
except (JWTExtendedException, PyJWTError):
except (JWTExtendedException, PyJWTError) as e:
app.logger.info(f"JWT error: {str(e)}")
raise AuthenticationError("Invalid token")

return wrapper
Expand Down
75 changes: 56 additions & 19 deletions app/helpers/brevo.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import time
from functools import wraps
from dataclasses import dataclass
from typing import Optional
Expand Down Expand Up @@ -38,6 +39,11 @@ class LinkCompanyContactData:
contact_id: int


@dataclass
class GetCompanyData:
company_id: str


@dataclass
class GetDealData:
deal_id: str
Expand All @@ -51,9 +57,8 @@ class UpdateDealStageData:


@dataclass
class GetDealsByPipelineData:
class GetAllDealsByPipelineData:
pipeline_id: str
limit: Optional[int] = None


def check_api_key(func):
Expand All @@ -69,7 +74,7 @@ def wrapper(self, *args, **kwargs):


class BrevoApiClient:
BASE_URL = "https://api.brevo.com/v3/"
BASE_URL = "https://api.brevo.com/v3"

def __init__(self, api_key):
self._configuration = sib_api_v3_sdk.Configuration()
Expand Down Expand Up @@ -115,7 +120,7 @@ def create_contact(self, data: CreateContactData):
@check_api_key
def create_company(self, data: CreateCompanyData):
try:
url = f"{self.BASE_URL}companies"
url = f"{self.BASE_URL}/companies"
attributes = {
"activation_mobilic": "Inscrite",
"siren": data.siren,
Expand All @@ -140,17 +145,27 @@ def create_company(self, data: CreateCompanyData):
@check_api_key
def link_company_and_contact(self, data: LinkCompanyContactData):
try:
url = f"{self.BASE_URL}companies/link-unlink/{data.company_id}"
url = f"{self.BASE_URL}/companies/link-unlink/{data.company_id}"
payload = {"linkContactIds": [data.contact_id]}
response = self._session.patch(url, json=payload)
return response
except ApiException as e:
raise BrevoRequestError(f"Request to Brevo API failed: {e}")

@check_api_key
def get_company(self, data: GetCompanyData):
try:
url = f"{self.BASE_URL}/companies/{data.company_id}"
response = self._session.get(url)
response.raise_for_status()
return response.json()
except ApiException as e:
raise BrevoRequestError(f"Request to Brevo API failed: {e}")

@check_api_key
def get_deal(self, data: GetDealData):
try:
url = f"{self.BASE_URL}crm/deals/{data.deal_id}"
url = f"{self.BASE_URL}/crm/deals/{data.deal_id}"
response = self._session.get(url)
response.raise_for_status()
return response.json()
Expand All @@ -160,7 +175,7 @@ def get_deal(self, data: GetDealData):
@check_api_key
def update_deal_stage(self, data: UpdateDealStageData):
try:
url = f"{self.BASE_URL}crm/deals/{data.deal_id}"
url = f"{self.BASE_URL}/crm/deals/{data.deal_id}"
payload = {
"attributes": {
"pipeline": data.pipeline_id,
Expand All @@ -178,23 +193,45 @@ def update_deal_stage(self, data: UpdateDealStageData):
raise BrevoRequestError(f"Request to Brevo API failed: {e}")

@check_api_key
def get_deals_by_pipeline(self, data: GetDealsByPipelineData):
def get_all_deals_by_pipeline(self, data: GetAllDealsByPipelineData):
try:
url = f"{self.BASE_URL}crm/deals"
params = {
"filters[attributes.pipeline]": data.pipeline_id,
"limit": data.limit,
}
response = self._session.get(url, params=params)
response.raise_for_status()
return response.json()
except ApiException as e:
all_deals = []
offset = 0
limit = 10000
# Brevo's maximum request limit per hour request (https://developers.brevo.com/docs/api-limits#general-rate-limiting)
max_attempts = 100

for _ in range(max_attempts):
params = {
"filters[attributes.pipeline]": data.pipeline_id,
"offset": offset,
"limit": limit,
}

response = self._session.get(
f"{self.BASE_URL}/crm/deals", params=params
)
# Retry after delay if rate-limited (https://developers.brevo.com/docs/api-limits#rate-limit-reset)
if response.status_code == 429:
app.logger.warning("Rate limit exceeded. Stopping batch.")
break

response.raise_for_status()
deals = response.json().get("items", [])
if not deals:
break

all_deals.extend(deals)
offset += limit

return {"items": all_deals}
except requests.exceptions.RequestException as e:
raise BrevoRequestError(f"Request to Brevo API failed: {e}")

@check_api_key
def get_all_pipelines(self):
try:
url = f"{self.BASE_URL}crm/pipeline/details/all"
url = f"{self.BASE_URL}/crm/pipeline/details/all"
response = self._session.get(url)
response.raise_for_status()
return response.json()
Expand All @@ -204,7 +241,7 @@ def get_all_pipelines(self):
@check_api_key
def get_pipeline_details(self, pipeline_id: str):
try:
url = f"{self.BASE_URL}crm/pipeline/details/{pipeline_id}"
url = f"{self.BASE_URL}/crm/pipeline/details/{pipeline_id}"
response = self._session.get(url)
response.raise_for_status()
return response.json()
Expand Down
17 changes: 10 additions & 7 deletions app/models/controller_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,27 +139,30 @@ def report_infractions(self):
)
observed_infractions = []
for regulatory_alert in regulatory_alerts:

extra = regulatory_alert.extra
if not extra or not "sanction_code" in extra:
continue

regulation_computations_for_the_day = [
rc
for rc in regulation_computations
if rc.day == regulatory_alert.day
]
if len(regulation_computations_for_the_day) == 0:
nb_rc_for_the_day = len(regulation_computations_for_the_day)
if nb_rc_for_the_day == 0:
continue
if (
len(regulation_computations_for_the_day) == 2
nb_rc_for_the_day == 2
and regulatory_alert.submitter_type != SubmitterType.ADMIN
):
continue
if (
regulation_computations_for_the_day[0].submitter_type
nb_rc_for_the_day == 1
and regulation_computations_for_the_day[0].submitter_type
!= regulatory_alert.submitter_type
):
continue

extra = regulatory_alert.extra
if not extra or not "sanction_code" in extra:
continue
sanction_code = extra.get("sanction_code")
is_reportable = "NATINF" in sanction_code
check_type = regulatory_alert.regulation_check.type
Expand Down
Loading

0 comments on commit e2e8fd7

Please sign in to comment.