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

Fix privacy policy validation #665

Merged
merged 2 commits into from
Dec 22, 2024
Merged
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
1 change: 1 addition & 0 deletions fittrackee/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from fittrackee.request import CustomRequest

VERSION = __version__ = '0.9.0b3'
DEFAULT_PRIVACY_POLICY_DATA = 'Sat, 30 Nov 2024 10:00:00 GMT'
REDIS_URL = os.getenv('REDIS_URL', 'redis://')
API_RATE_LIMITS = os.environ.get('API_RATE_LIMITS', '300 per 5 minutes').split(
','
Expand Down
6 changes: 5 additions & 1 deletion fittrackee/application/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ def serialize(self) -> Dict:
'max_users': self.max_users,
'map_attribution': self.map_attribution,
'privacy_policy': self.privacy_policy,
'privacy_policy_date': self.privacy_policy_date,
'privacy_policy_date': (
self.privacy_policy_date
if self.privacy_policy
else current_app.config['DEFAULT_PRIVACY_POLICY_DATA']
),
'stats_workouts_limit': self.stats_workouts_limit,
'version': current_app.config['VERSION'],
'weather_provider': (
Expand Down
10 changes: 9 additions & 1 deletion fittrackee/application/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from datetime import datetime
from typing import Dict, List

from flask import Flask
Expand Down Expand Up @@ -35,7 +36,14 @@ def update_app_config_from_database(
current_app.config['is_registration_enabled'] = (
db_config.is_registration_enabled
)
current_app.config['privacy_policy_date'] = db_config.privacy_policy_date
current_app.config['privacy_policy_date'] = (
db_config.privacy_policy_date
if db_config.privacy_policy_date
else datetime.strptime(
current_app.config['DEFAULT_PRIVACY_POLICY_DATA'],
'%a, %d %b %Y %H:%M:%S GMT',
)
)
current_app.config['stats_workouts_limit'] = db_config.stats_workouts_limit


Expand Down
3 changes: 2 additions & 1 deletion fittrackee/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from flask import current_app
from sqlalchemy.pool import NullPool

from fittrackee import VERSION
from fittrackee import DEFAULT_PRIVACY_POLICY_DATA, VERSION
from fittrackee.languages import SUPPORTED_LANGUAGES

broker: Union[Type['RedisBroker'], Type['StubBroker']] = (
Expand Down Expand Up @@ -68,6 +68,7 @@ class BaseConfig:
OAUTH2_REFRESH_TOKEN_GENERATOR = True
DATA_EXPORT_EXPIRATION = 24 # hours
VERSION = VERSION
DEFAULT_PRIVACY_POLICY_DATA = DEFAULT_PRIVACY_POLICY_DATA


class DevelopmentConfig(BaseConfig):
Expand Down
4 changes: 2 additions & 2 deletions fittrackee/dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
<link rel="stylesheet" href="/static/css/fork-awesome.min.css"/>
<link rel="stylesheet" href="/static/css/leaflet.css"/>
<title>FitTrackee</title>
<script type="module" crossorigin src="/static/index-DRHKjcOd.js"></script>
<script type="module" crossorigin src="/static/index-DVm2A7MB.js"></script>
<link rel="modulepreload" crossorigin href="/static/charts-BDOr5tL2.js">
<link rel="modulepreload" crossorigin href="/static/maps-DkiRMund.js">
<link rel="stylesheet" crossorigin href="/static/css/maps-CIGW-MKW.css">
<link rel="stylesheet" crossorigin href="/static/css/index-BmMN6Jqs.css">
<link rel="stylesheet" crossorigin href="/static/css/index-D04_aUPJ.css">
</head>
<body>
<div id="app"></div>
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions fittrackee/tests/application/test_app_config_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ def test_it_updates_privacy_policy(
] == privacy_policy_date.strftime('%a, %d %b %Y %H:%M:%S GMT')

@pytest.mark.parametrize('input_privacy_policy', ['', None])
def test_it_empties_privacy_policy_date_when_no_privacy_policy(
def test_it_return_default_privacy_policy_date_when_no_privacy_policy(
self,
app: Flask,
user_1_admin: User,
Expand All @@ -487,7 +487,10 @@ def test_it_empties_privacy_policy_date_when_no_privacy_policy(
data = json.loads(response.data.decode())
assert 'success' in data['status']
assert data['data']['privacy_policy'] is None
assert data['data']['privacy_policy_date'] is None
assert (
data['data']['privacy_policy_date']
== app.config['DEFAULT_PRIVACY_POLICY_DATA']
)

@pytest.mark.parametrize(
'client_scope, can_access',
Expand Down
17 changes: 15 additions & 2 deletions fittrackee/tests/application/test_app_config_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import pytest
from flask import Flask

from fittrackee import VERSION
from fittrackee import DEFAULT_PRIVACY_POLICY_DATA, VERSION
from fittrackee.application.models import AppConfig
from fittrackee.users.models import User

Expand Down Expand Up @@ -93,7 +93,20 @@ def test_it_returns_weather_provider(
== expected_weather_provider
)

def test_it_returns_privacy_policy(self, app: Flask) -> None:
def test_it_returns_only_privacy_policy_date_when_no_custom_privacy(
self, app: Flask
) -> None:
app_config = AppConfig.query.first()

serialized_app_config = app_config.serialize()

assert serialized_app_config["privacy_policy"] is None
assert (
serialized_app_config["privacy_policy_date"]
== DEFAULT_PRIVACY_POLICY_DATA
)

def test_it_returns_custom_privacy_policy(self, app: Flask) -> None:
app_config = AppConfig.query.first()
privacy_policy = random_string()
privacy_policy_date = datetime.utcnow()
Expand Down
26 changes: 25 additions & 1 deletion fittrackee/tests/application/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from flask import Flask

from fittrackee import VERSION
from fittrackee import DEFAULT_PRIVACY_POLICY_DATA, VERSION


class TestDevelopmentConfig:
Expand Down Expand Up @@ -30,6 +30,14 @@ def test_it_returns_application_version(self, app: Flask) -> None:

assert app.config['VERSION'] == VERSION

def test_it_returns_default_privacy_policy_date(self, app: Flask) -> None:
app.config.from_object('fittrackee.config.DevelopmentConfig')

assert (
app.config['DEFAULT_PRIVACY_POLICY_DATA']
== DEFAULT_PRIVACY_POLICY_DATA
)


class TestTestingConfig:
def test_debug_is_enabled(self, app: Flask) -> None:
Expand Down Expand Up @@ -60,6 +68,14 @@ def test_it_returns_application_version(self, app: Flask) -> None:

assert app.config['VERSION'] == VERSION

def test_it_returns_default_privacy_policy_date(self, app: Flask) -> None:
app.config.from_object('fittrackee.config.DevelopmentConfig')

assert (
app.config['DEFAULT_PRIVACY_POLICY_DATA']
== DEFAULT_PRIVACY_POLICY_DATA
)


class TestProductionConfig:
def test_debug_is_disabled(self, app: Flask) -> None:
Expand All @@ -85,3 +101,11 @@ def test_it_returns_application_version(self, app: Flask) -> None:
app.config.from_object('fittrackee.config.ProductionConfig')

assert app.config['VERSION'] == VERSION

def test_it_returns_default_privacy_policy_date(self, app: Flask) -> None:
app.config.from_object('fittrackee.config.DevelopmentConfig')

assert (
app.config['DEFAULT_PRIVACY_POLICY_DATA']
== DEFAULT_PRIVACY_POLICY_DATA
)
23 changes: 15 additions & 8 deletions fittrackee/tests/users/test_users_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,27 +187,34 @@ def test_it_returns_workouts_infos(self, app: Flask, user_1: User) -> None:

self.assert_workouts_keys_are_present(serialized_user)

def test_it_returns_user_did_not_accept_default_privacy_policy(
def test_it_returns_none_when_user_did_not_accept_default_privacy_policy(
self, app: Flask, user_1: User
) -> None:
# default privacy policy
app.config['privacy_policy_date'] = None
user_1.accepted_policy_date = None
serialized_user = user_1.serialize(current_user=user_1, light=False)

assert serialized_user['accepted_privacy_policy'] is False
assert serialized_user['accepted_privacy_policy'] is None

def test_it_returns_user_did_accept_default_privacy_policy(
def test_it_returns_true_user_did_accept_default_privacy_policy(
self, app: Flask, user_1: User
) -> None:
# default privacy policy
app.config['privacy_policy_date'] = None
user_1.accepted_policy_date = datetime.utcnow()
serialized_user = user_1.serialize(current_user=user_1, light=False)

assert serialized_user['accepted_privacy_policy'] is True

def test_it_returns_user_did_not_accept_last_policy(
def test_it_returns_false_when_user_did_not_accept_last_default_policy(
self, app: Flask, user_1: User
) -> None:
user_1.accepted_policy_date = datetime.strptime(
app.config['DEFAULT_PRIVACY_POLICY_DATA'],
'%a, %d %b %Y %H:%M:%S GMT',
) - timedelta(days=1)
serialized_user = user_1.serialize(current_user=user_1, light=False)

assert serialized_user['accepted_privacy_policy'] is False

def test_it_returns_false_when_user_did_not_accept_last_custom_policy(
self, app: Flask, user_1: User
) -> None:
user_1.accepted_policy_date = datetime.utcnow()
Expand Down
6 changes: 2 additions & 4 deletions fittrackee/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -764,12 +764,10 @@ def serialize(
]

if is_auth_user(role):
accepted_privacy_policy = False
accepted_privacy_policy = None
if self.accepted_policy_date:
accepted_privacy_policy = (
True
if current_app.config['privacy_policy_date'] is None
else current_app.config['privacy_policy_date']
current_app.config['privacy_policy_date']
< self.accepted_policy_date
)
serialized_user = {
Expand Down
5 changes: 1 addition & 4 deletions fittrackee_client/src/components/PrivacyPolicy.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
const { appConfig } = useApp()
const { dateFormat, timezone } = useAuthUser()

const fittrackeePrivatePolicyDate = 'Sat, 30 Nov 2024 10:00:00 GMT'
const paragraphs = [
'DATA_COLLECTED',
'INFORMATION_USAGE',
Expand All @@ -53,9 +52,7 @@

function getPolicyDate() {
return formatDate(
appConfig.value.privacy_policy && appConfig.value.privacy_policy_date
? `${appConfig.value.privacy_policy_date}`
: fittrackeePrivatePolicyDate,
appConfig.value.privacy_policy_date,
timezone.value,
dateFormat.value,
false
Expand Down
15 changes: 14 additions & 1 deletion fittrackee_client/src/components/PrivacyPolicyToAccept.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<template>
<div class="privacy-policy-message">
<span>
<i18n-t keypath="user.LAST_PRIVACY_POLICY_TO_VALIDATE">
<i18n-t
:keypath="`user.${isPrivacyUpdated ? 'LAST_' : ''}PRIVACY_POLICY_TO_VALIDATE`"
>
<router-link to="/profile/edit/privacy-policy" class="policy-link">
{{ $t('user.REVIEW') }}
</router-link>
Expand All @@ -10,6 +12,17 @@
</div>
</template>

<script lang="ts" setup>
import { toRefs } from 'vue'

interface Props {
isPrivacyUpdated: boolean
}
const props = defineProps<Props>()

const { isPrivacyUpdated } = toRefs(props)
</script>

<style scoped lang="scss">
@import '~@/scss/vars.scss';

Expand Down
1 change: 1 addition & 0 deletions fittrackee_client/src/locales/en/user.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"WEAK": "weak"
},
"PASSWORD_UPDATED": "Your password have been updated. Click {0} to log in.",
"PRIVACY_POLICY_TO_VALIDATE": "Please {0} the privacy policy before proceeding.",
"PROFILE": {
"ACCOUNT_EDITION": "Account edition",
"ASCENT_DATA": "Ascent-related data (records, total)",
Expand Down
2 changes: 2 additions & 0 deletions fittrackee_client/src/locales/fr/user.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@
"WEAK": "faible"
},
"PASSWORD_UPDATED": "Votre mot de passe a été mis à jour. Cliquez {0} pour vous connecter.",

"PRIVACY_POLICY_TO_VALIDATE": "Veuillez {0} la politique de confidentialité avant de poursuivre.",
"PROFILE": {
"ACCOUNT_EDITION": "Mise à jour du compte",
"ASCENT_DATA": "Données relatives au dénivelé positif (records, total)",
Expand Down
2 changes: 1 addition & 1 deletion fittrackee_client/src/types/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type TAppConfig = {
max_users: number
max_zip_file_size: number
privacy_policy: string | null
privacy_policy_date: string | null
privacy_policy_date: string
stats_workouts_limit: number
version: string
weather_provider: string | null
Expand Down
2 changes: 1 addition & 1 deletion fittrackee_client/src/types/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export interface IUserProfile extends IUserLightProfile {
}

export interface IAuthUserProfile extends IUserProfile {
accepted_privacy_policy: boolean
accepted_privacy_policy: boolean | null
display_ascent: boolean
email: string
hide_profile_in_users_directory: boolean
Expand Down
4 changes: 3 additions & 1 deletion fittrackee_client/src/utils/dates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ export const getDateFormat = (
dateFormat: string,
language: TLanguage
): string => {
return dateFormat === 'date_string' ? dateStringFormats[language] : dateFormat
return dateFormat === 'date_string'
? dateStringFormats[language]
: dateFormat || 'MM/dd/yyyy'
}

export const formatDate = (
Expand Down
6 changes: 4 additions & 2 deletions fittrackee_client/src/views/Dashboard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@
</div>
<div
class="container privacy-policy-message"
v-if="!authUser.accepted_privacy_policy"
v-if="authUser.accepted_privacy_policy !== true"
>
<PrivacyPolicyToAccept />
<PrivacyPolicyToAccept
:is-privacy-updated="authUser.accepted_privacy_policy === false"
/>
</div>
<div class="container">
<UserStatsCards :user="authUser" />
Expand Down
7 changes: 7 additions & 0 deletions fittrackee_client/tests/unit/utils/dates.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,13 @@ describe('getDateFormat', () => {
},
expectedFormat: 'yyyy-MM-dd',
},
{
inputParams: {
dateFormat: '',
language: 'fr',
},
expectedFormat: 'MM/dd/yyyy',
},
{
inputParams: {
dateFormat: 'date_string',
Expand Down
Loading