API & Client - update registration activation on user register/delete
+ minor refactor on administration (fix #15)
This commit is contained in:
		@@ -1,4 +1,6 @@
 | 
				
			|||||||
from fittrackee_api import db
 | 
					from fittrackee_api import db
 | 
				
			||||||
 | 
					from flask import current_app
 | 
				
			||||||
 | 
					from sqlalchemy.event import listens_for
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ..users.models import User
 | 
					from ..users.models import User
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,3 +28,25 @@ class AppConfig(db.Model):
 | 
				
			|||||||
            "max_zip_file_size": self.max_zip_file_size,
 | 
					            "max_zip_file_size": self.max_zip_file_size,
 | 
				
			||||||
            "max_users": self.max_users,
 | 
					            "max_users": self.max_users,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def update_app_config():
 | 
				
			||||||
 | 
					    config = AppConfig.query.first()
 | 
				
			||||||
 | 
					    if config:
 | 
				
			||||||
 | 
					        current_app.config[
 | 
				
			||||||
 | 
					            'is_registration_enabled'
 | 
				
			||||||
 | 
					        ] = config.is_registration_enabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@listens_for(User, 'after_insert')
 | 
				
			||||||
 | 
					def on_user_insert(mapper, connection, user):
 | 
				
			||||||
 | 
					    @listens_for(db.Session, 'after_flush', once=True)
 | 
				
			||||||
 | 
					    def receive_after_flush(session, context):
 | 
				
			||||||
 | 
					        update_app_config()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@listens_for(User, 'after_delete')
 | 
				
			||||||
 | 
					def on_user_delete(mapper, connection, old_user):
 | 
				
			||||||
 | 
					    @listens_for(db.Session, 'after_flush', once=True)
 | 
				
			||||||
 | 
					    def receive_after_flush(session, context):
 | 
				
			||||||
 | 
					        update_app_config()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,7 +62,6 @@ def app_config():
 | 
				
			|||||||
    config.max_single_file_size = 1048576
 | 
					    config.max_single_file_size = 1048576
 | 
				
			||||||
    config.max_zip_file_size = 10485760
 | 
					    config.max_zip_file_size = 10485760
 | 
				
			||||||
    config.max_users = 0
 | 
					    config.max_users = 0
 | 
				
			||||||
    config.registration = False
 | 
					 | 
				
			||||||
    db.session.add(config)
 | 
					    db.session.add(config)
 | 
				
			||||||
    db.session.commit()
 | 
					    db.session.commit()
 | 
				
			||||||
    return config
 | 
					    return config
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -836,3 +836,70 @@ def test_update_user_invalid_picture(app, user_1):
 | 
				
			|||||||
    assert data['status'] == 'fail'
 | 
					    assert data['status'] == 'fail'
 | 
				
			||||||
    assert data['message'] == 'File extension not allowed.'
 | 
					    assert data['message'] == 'File extension not allowed.'
 | 
				
			||||||
    assert response.status_code == 400
 | 
					    assert response.status_code == 400
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_it_disables_registration_on_user_registration(
 | 
				
			||||||
 | 
					    app_no_config, app_config, user_1_admin, user_2
 | 
				
			||||||
 | 
					):
 | 
				
			||||||
 | 
					    app_config.max_users = 3
 | 
				
			||||||
 | 
					    client = app_no_config.test_client()
 | 
				
			||||||
 | 
					    client.post(
 | 
				
			||||||
 | 
					        '/api/auth/register',
 | 
				
			||||||
 | 
					        data=json.dumps(
 | 
				
			||||||
 | 
					            dict(
 | 
				
			||||||
 | 
					                username='sam',
 | 
				
			||||||
 | 
					                email='sam@test.com',
 | 
				
			||||||
 | 
					                password='12345678',
 | 
				
			||||||
 | 
					                password_conf='12345678',
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        content_type='application/json',
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    response = client.post(
 | 
				
			||||||
 | 
					        '/api/auth/register',
 | 
				
			||||||
 | 
					        data=json.dumps(
 | 
				
			||||||
 | 
					            dict(
 | 
				
			||||||
 | 
					                username='new',
 | 
				
			||||||
 | 
					                email='new@test.com',
 | 
				
			||||||
 | 
					                password='12345678',
 | 
				
			||||||
 | 
					                password_conf='12345678',
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        content_type='application/json',
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    assert response.status_code == 403
 | 
				
			||||||
 | 
					    data = json.loads(response.data.decode())
 | 
				
			||||||
 | 
					    assert data['status'] == 'error'
 | 
				
			||||||
 | 
					    assert data['message'] == 'Error. Registration is disabled.'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_it_does_not_disable_registration_on_user_registration(
 | 
				
			||||||
 | 
					    app_no_config, app_config, user_1_admin, user_2,
 | 
				
			||||||
 | 
					):
 | 
				
			||||||
 | 
					    app_config.max_users = 4
 | 
				
			||||||
 | 
					    client = app_no_config.test_client()
 | 
				
			||||||
 | 
					    client.post(
 | 
				
			||||||
 | 
					        '/api/auth/register',
 | 
				
			||||||
 | 
					        data=json.dumps(
 | 
				
			||||||
 | 
					            dict(
 | 
				
			||||||
 | 
					                username='sam',
 | 
				
			||||||
 | 
					                email='sam@test.com',
 | 
				
			||||||
 | 
					                password='12345678',
 | 
				
			||||||
 | 
					                password_conf='12345678',
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        content_type='application/json',
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    response = client.post(
 | 
				
			||||||
 | 
					        '/api/auth/register',
 | 
				
			||||||
 | 
					        data=json.dumps(
 | 
				
			||||||
 | 
					            dict(
 | 
				
			||||||
 | 
					                username='new',
 | 
				
			||||||
 | 
					                email='new@test.com',
 | 
				
			||||||
 | 
					                password='12345678',
 | 
				
			||||||
 | 
					                password_conf='12345678',
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        content_type='application/json',
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    assert response.status_code == 201
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1252,3 +1252,70 @@ def test_admin_can_not_delete_its_own_account_if_no_other_admin(
 | 
				
			|||||||
        'You can not delete your account, no other user has admin rights.'
 | 
					        'You can not delete your account, no other user has admin rights.'
 | 
				
			||||||
        in data['message']
 | 
					        in data['message']
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_it_enables_registration_on_user_delete(
 | 
				
			||||||
 | 
					    app_no_config, app_config, user_1_admin, user_2, user_3
 | 
				
			||||||
 | 
					):
 | 
				
			||||||
 | 
					    app_config.max_users = 3
 | 
				
			||||||
 | 
					    client = app_no_config.test_client()
 | 
				
			||||||
 | 
					    resp_login = client.post(
 | 
				
			||||||
 | 
					        '/api/auth/login',
 | 
				
			||||||
 | 
					        data=json.dumps(dict(email='admin@example.com', password='12345678')),
 | 
				
			||||||
 | 
					        content_type='application/json',
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    client.delete(
 | 
				
			||||||
 | 
					        '/api/users/toto',
 | 
				
			||||||
 | 
					        headers=dict(
 | 
				
			||||||
 | 
					            Authorization='Bearer '
 | 
				
			||||||
 | 
					            + json.loads(resp_login.data.decode())['auth_token']
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    response = client.post(
 | 
				
			||||||
 | 
					        '/api/auth/register',
 | 
				
			||||||
 | 
					        data=json.dumps(
 | 
				
			||||||
 | 
					            dict(
 | 
				
			||||||
 | 
					                username='justatest',
 | 
				
			||||||
 | 
					                email='test@test.com',
 | 
				
			||||||
 | 
					                password='12345678',
 | 
				
			||||||
 | 
					                password_conf='12345678',
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        content_type='application/json',
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    assert response.status_code == 201
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_it_does_not_enable_registration_on_user_delete(
 | 
				
			||||||
 | 
					    app_no_config, app_config, user_1_admin, user_2, user_3
 | 
				
			||||||
 | 
					):
 | 
				
			||||||
 | 
					    app_config.max_users = 2
 | 
				
			||||||
 | 
					    client = app_no_config.test_client()
 | 
				
			||||||
 | 
					    resp_login = client.post(
 | 
				
			||||||
 | 
					        '/api/auth/login',
 | 
				
			||||||
 | 
					        data=json.dumps(dict(email='admin@example.com', password='12345678')),
 | 
				
			||||||
 | 
					        content_type='application/json',
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    client.delete(
 | 
				
			||||||
 | 
					        '/api/users/toto',
 | 
				
			||||||
 | 
					        headers=dict(
 | 
				
			||||||
 | 
					            Authorization='Bearer '
 | 
				
			||||||
 | 
					            + json.loads(resp_login.data.decode())['auth_token']
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    response = client.post(
 | 
				
			||||||
 | 
					        '/api/auth/register',
 | 
				
			||||||
 | 
					        data=json.dumps(
 | 
				
			||||||
 | 
					            dict(
 | 
				
			||||||
 | 
					                username='justatest',
 | 
				
			||||||
 | 
					                email='test@test.com',
 | 
				
			||||||
 | 
					                password='12345678',
 | 
				
			||||||
 | 
					                password_conf='12345678',
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        content_type='application/json',
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    assert response.status_code == 403
 | 
				
			||||||
 | 
					    data = json.loads(response.data.decode())
 | 
				
			||||||
 | 
					    assert data['status'] == 'error'
 | 
				
			||||||
 | 
					    assert data['message'] == 'Error. Registration is disabled.'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ import FitTrackeeApi from '../fitTrackeeApi/auth'
 | 
				
			|||||||
import { history } from '../index'
 | 
					import { history } from '../index'
 | 
				
			||||||
import { generateIds } from '../utils'
 | 
					import { generateIds } from '../utils'
 | 
				
			||||||
import { getOrUpdateData, setError, updateLanguage } from './index'
 | 
					import { getOrUpdateData, setError, updateLanguage } from './index'
 | 
				
			||||||
 | 
					import { getAppData } from './application'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const AuthError = message => ({ type: 'AUTH_ERROR', message })
 | 
					const AuthError = message => ({ type: 'AUTH_ERROR', message })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -50,6 +51,9 @@ export const loginOrRegister = (target, formData) => dispatch =>
 | 
				
			|||||||
    .then(ret => {
 | 
					    .then(ret => {
 | 
				
			||||||
      if (ret.status === 'success') {
 | 
					      if (ret.status === 'success') {
 | 
				
			||||||
        window.localStorage.setItem('authToken', ret.auth_token)
 | 
					        window.localStorage.setItem('authToken', ret.auth_token)
 | 
				
			||||||
 | 
					        if (target === 'register') {
 | 
				
			||||||
 | 
					          dispatch(getAppData('config'))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        return dispatch(getProfile())
 | 
					        return dispatch(getProfile())
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return dispatch(AuthError(ret.message))
 | 
					      return dispatch(AuthError(ret.message))
 | 
				
			||||||
@@ -138,6 +142,7 @@ export const deleteUser = (username, isAdmin = false) => dispatch =>
 | 
				
			|||||||
  FitTrackeeGenericApi.deleteData('users', username)
 | 
					  FitTrackeeGenericApi.deleteData('users', username)
 | 
				
			||||||
    .then(ret => {
 | 
					    .then(ret => {
 | 
				
			||||||
      if (ret.status === 204) {
 | 
					      if (ret.status === 204) {
 | 
				
			||||||
 | 
					        dispatch(getAppData('config'))
 | 
				
			||||||
        if (isAdmin) {
 | 
					        if (isAdmin) {
 | 
				
			||||||
          history.push('/admin/users')
 | 
					          history.push('/admin/users')
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,8 +82,15 @@ class AdminApplication extends React.Component {
 | 
				
			|||||||
                      >
 | 
					                      >
 | 
				
			||||||
                        {t(
 | 
					                        {t(
 | 
				
			||||||
                          // eslint-disable-next-line max-len
 | 
					                          // eslint-disable-next-line max-len
 | 
				
			||||||
                          'administration:Max. number of active users (if 0, no limitation)'
 | 
					                          'administration:Max. number of active users'
 | 
				
			||||||
                        )}
 | 
					                        )}
 | 
				
			||||||
 | 
					                        <sup>
 | 
				
			||||||
 | 
					                          <i
 | 
				
			||||||
 | 
					                            className="fa fa-question-circle"
 | 
				
			||||||
 | 
					                            aria-hidden="true"
 | 
				
			||||||
 | 
					                            title={t('administration:if 0, no limitation')}
 | 
				
			||||||
 | 
					                          />
 | 
				
			||||||
 | 
					                        </sup>
 | 
				
			||||||
                        :
 | 
					                        :
 | 
				
			||||||
                      </label>
 | 
					                      </label>
 | 
				
			||||||
                      <input
 | 
					                      <input
 | 
				
			||||||
@@ -197,7 +204,6 @@ class AdminApplication extends React.Component {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export default connect(
 | 
					export default connect(
 | 
				
			||||||
  state => ({
 | 
					  state => ({
 | 
				
			||||||
    appConfig: state.application.config,
 | 
					 | 
				
			||||||
    message: state.message,
 | 
					    message: state.message,
 | 
				
			||||||
  }),
 | 
					  }),
 | 
				
			||||||
  dispatch => ({
 | 
					  dispatch => ({
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@ import { Link } from 'react-router-dom'
 | 
				
			|||||||
import AdminStats from './AdminStats'
 | 
					import AdminStats from './AdminStats'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function AdminDashboard(props) {
 | 
					export default function AdminDashboard(props) {
 | 
				
			||||||
  const { t } = props
 | 
					  const { appConfig, t } = props
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div className="card activity-card">
 | 
					    <div className="card activity-card">
 | 
				
			||||||
      <div className="card-header">
 | 
					      <div className="card-header">
 | 
				
			||||||
@@ -27,7 +27,15 @@ export default function AdminDashboard(props) {
 | 
				
			|||||||
            {t(
 | 
					            {t(
 | 
				
			||||||
              'administration:Update application configuration ' +
 | 
					              'administration:Update application configuration ' +
 | 
				
			||||||
                '(maximum number of registered users, maximum files size).'
 | 
					                '(maximum number of registered users, maximum files size).'
 | 
				
			||||||
            )}{' '}
 | 
					            )}
 | 
				
			||||||
 | 
					            <br />
 | 
				
			||||||
 | 
					            <strong>
 | 
				
			||||||
 | 
					              {t(
 | 
				
			||||||
 | 
					                `administration:Registration is currently ${
 | 
				
			||||||
 | 
					                  appConfig.is_registration_enabled ? 'enabled' : 'disabled'
 | 
				
			||||||
 | 
					                }.`
 | 
				
			||||||
 | 
					              )}
 | 
				
			||||||
 | 
					            </strong>
 | 
				
			||||||
          </dd>
 | 
					          </dd>
 | 
				
			||||||
          <br />
 | 
					          <br />
 | 
				
			||||||
          <dt>
 | 
					          <dt>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,7 @@ import AdminUsers from './AdminUsers'
 | 
				
			|||||||
import NotFound from './../Others/NotFound'
 | 
					import NotFound from './../Others/NotFound'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function Admin(props) {
 | 
					function Admin(props) {
 | 
				
			||||||
  const { t, user } = props
 | 
					  const { appConfig, t, user } = props
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <>
 | 
					    <>
 | 
				
			||||||
      <Helmet>
 | 
					      <Helmet>
 | 
				
			||||||
@@ -23,12 +23,12 @@ function Admin(props) {
 | 
				
			|||||||
            <Route
 | 
					            <Route
 | 
				
			||||||
              exact
 | 
					              exact
 | 
				
			||||||
              path="/admin"
 | 
					              path="/admin"
 | 
				
			||||||
              render={() => <AdminDashboard t={t} />}
 | 
					              render={() => <AdminDashboard appConfig={appConfig} t={t} />}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
            <Route
 | 
					            <Route
 | 
				
			||||||
              exact
 | 
					              exact
 | 
				
			||||||
              path="/admin/application"
 | 
					              path="/admin/application"
 | 
				
			||||||
              render={() => <AdminApplication t={t} />}
 | 
					              render={() => <AdminApplication appConfig={appConfig} t={t} />}
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
            <Route
 | 
					            <Route
 | 
				
			||||||
              exact
 | 
					              exact
 | 
				
			||||||
@@ -52,6 +52,7 @@ function Admin(props) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export default withTranslation()(
 | 
					export default withTranslation()(
 | 
				
			||||||
  connect(state => ({
 | 
					  connect(state => ({
 | 
				
			||||||
 | 
					    appConfig: state.application.config,
 | 
				
			||||||
    user: state.user,
 | 
					    user: state.user,
 | 
				
			||||||
  }))(Admin)
 | 
					  }))(Admin)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,14 +13,17 @@
 | 
				
			|||||||
  "Enable/disable sports.": "Enable/disable sports.",
 | 
					  "Enable/disable sports.": "Enable/disable sports.",
 | 
				
			||||||
  "FitTrackee administration": "FitTrackee administration",
 | 
					  "FitTrackee administration": "FitTrackee administration",
 | 
				
			||||||
  "id": "id",
 | 
					  "id": "id",
 | 
				
			||||||
 | 
					  "if 0, no limitation": "if 0, no limitation",
 | 
				
			||||||
  "Image": "Image",
 | 
					  "Image": "Image",
 | 
				
			||||||
  "Label": "Label",
 | 
					  "Label": "Label",
 | 
				
			||||||
  "Max. number of active users (if 0, no limitation)": "Max. number of active users",
 | 
					  "Max. number of active users": "Max. number of active users",
 | 
				
			||||||
  "Max. files of zip archive": "Max. files of zip archive",
 | 
					  "Max. files of zip archive": "Max. files of zip archive",
 | 
				
			||||||
  "Max. size of uploaded files": "Max. size of uploaded files",
 | 
					  "Max. size of uploaded files": "Max. size of uploaded files",
 | 
				
			||||||
  "Max. size of uploaded files (in Mb)": "Max. size of uploaded files (in Mb)",
 | 
					  "Max. size of uploaded files (in Mb)": "Max. size of uploaded files (in Mb)",
 | 
				
			||||||
  "Max. size of zip archive": "Max. size of zip archive",
 | 
					  "Max. size of zip archive": "Max. size of zip archive",
 | 
				
			||||||
  "Max. size of zip archive (in Mb)": "Max. size of zip archive (in Mb)",
 | 
					  "Max. size of zip archive (in Mb)": "Max. size of zip archive (in Mb)",
 | 
				
			||||||
 | 
					  "Registration is currently disabled.": "Registration is currently disabled.",
 | 
				
			||||||
 | 
					  "Registration is currently enabled.": "Registration is currently enabled.",
 | 
				
			||||||
  "Remove admin rights": "Remove admin rights",
 | 
					  "Remove admin rights": "Remove admin rights",
 | 
				
			||||||
  "Sports": "Sports",
 | 
					  "Sports": "Sports",
 | 
				
			||||||
  "Update application configuration (maximum number of registered users, maximum files size).": "Update application configuration (maximum number of registered users, maximum files size).",
 | 
					  "Update application configuration (maximum number of registered users, maximum files size).": "Update application configuration (maximum number of registered users, maximum files size).",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,14 +13,17 @@
 | 
				
			|||||||
  "Enable/disable sports.": "Activer/désactiver des sports.",
 | 
					  "Enable/disable sports.": "Activer/désactiver des sports.",
 | 
				
			||||||
  "FitTrackee administration": "Administration de FitTrackee",
 | 
					  "FitTrackee administration": "Administration de FitTrackee",
 | 
				
			||||||
  "id": "id",
 | 
					  "id": "id",
 | 
				
			||||||
 | 
					  "if 0, no limitation": "si égal à 0, pas limite d'inscription",
 | 
				
			||||||
  "Image": "Image",
 | 
					  "Image": "Image",
 | 
				
			||||||
  "Label": "Label",
 | 
					  "Label": "Label",
 | 
				
			||||||
  "Max. number of active users (if 0, no limitation)": "Nombre maximum d'utilisateurs actifs",
 | 
					  "Max. number of active users": "Nombre maximum d'utilisateurs actifs",
 | 
				
			||||||
  "Max. files of zip archive": "Nombre max. de fichiers dans une archive zip",
 | 
					  "Max. files of zip archive": "Nombre max. de fichiers dans une archive zip",
 | 
				
			||||||
  "Max. size of uploaded files": "Taille max. des fichiers",
 | 
					  "Max. size of uploaded files": "Taille max. des fichiers",
 | 
				
			||||||
  "Max. size of uploaded files (in Mb)": "Taille max. des fichiers (en Mo)",
 | 
					  "Max. size of uploaded files (in Mb)": "Taille max. des fichiers (en Mo)",
 | 
				
			||||||
  "Max. size of zip archive": "Taille max. des archives zip",
 | 
					  "Max. size of zip archive": "Taille max. des archives zip",
 | 
				
			||||||
  "Max. size of zip archive (in Mb)": "Taille max. des archives zip (en Mo)",
 | 
					  "Max. size of zip archive (in Mb)": "Taille max. des archives zip (en Mo)",
 | 
				
			||||||
 | 
					  "Registration is currently disabled.": "Les inscriptions sont actuellement désactivées",
 | 
				
			||||||
 | 
					  "Registration is currently enabled.": "Les inscriptions sont actuellement activées",
 | 
				
			||||||
  "Remove admin rights": "Retirer des droits d'admin",
 | 
					  "Remove admin rights": "Retirer des droits d'admin",
 | 
				
			||||||
  "Sports": "Sports",
 | 
					  "Sports": "Sports",
 | 
				
			||||||
  "Update application configuration (maximum number of registered users, maximum files size).": "Configurer l'application (nombre maximum d'utilisateurs inscrits, taille maximale des fichers).",
 | 
					  "Update application configuration (maximum number of registered users, maximum files size).": "Configurer l'application (nombre maximum d'utilisateurs inscrits, taille maximale des fichers).",
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user