Commit e9e8ecbe authored by Florent Chehab's avatar Florent Chehab

Merge branch 'better_api_integration' into 'master'

Better api integration

See merge request chehabfl/outgoing_rex!24
parents 6ebf4368 86794957
Pipeline #26849 passed with stages
in 2 minutes and 32 seconds
...@@ -7,6 +7,9 @@ install_backend: ...@@ -7,6 +7,9 @@ install_backend:
generate_backend: generate_backend:
python ./backend/generate/generate_all.py python ./backend/generate/generate_all.py
generate_frontend:
python ./frontend/generate/generate_frontend_files.py
test_backend: generate_backend test_backend: generate_backend
pytest pytest
......
# THIS FILE IS USED TO GENERATE OTHER VERY IMPORTANT FILES
# BOTH IN THE FRONTEND AND IN THE BACKEND !
# TAKE CARE WHEN MODYFING IT ;)
# model : the model name (may be null)
# viewset : the viewset name for the api
# api_end_pont : the main part of the url for making request to the api
# This string will also be used for naming variables in JS !!
# So no weird characters there please...
# versionned: boolean to specify wether this model is versionned or not
# api_attr : to specify some attributes that may be captured
# and used in the viewset
# requires_testing: boolean to tell if this viewset is only availble in
# a testing environment.
- model: Country - model: Country
viewset: CountryViewSet viewset: CountryViewSet
import_location: location import_location: location
api_end_point: country api_end_point: countries
- model: City - model: City
viewset: CityViewSet viewset: CityViewSet
import_location: location import_location: location
api_end_point: city api_end_point: cities
- model: Tag
viewset: TagViewSet
import_location: tag
api_end_point: tag
- model: UniversityTaggedItem - model: University
viewset: UniversityTaggedItemViewSet viewset: UniversityViewSet
import_location: university import_location: university
api_end_point: university_more_tmp api_end_point: universities
versionned: true
- model: CampusTaggedItem - model: Campus
viewset: CampusTaggedItemViewSet viewset: CampusViewSet
import_location: university import_location: university
api_end_point: campus_more_tmp api_end_point: campuses
versionned: true versionned: true
- model: CountryTaggedItem
viewset: CountryTaggedItemViewSet
import_location: location
api_end_point: country_more_tmp
versionned: true
- model: CityTaggedItem - model: UserData
viewset: CityTaggedItemViewSet viewset: UserDataViewSet
import_location: location import_location: user
api_end_point: city_more_tmp api_end_point: userData
versionned: true api_name: user-data-detail
- model: Tag
viewset: TagViewSet
import_location: tag
api_end_point: tags
- model: Currency - model: Currency
viewset: CurrencyViewSet viewset: CurrencyViewSet
import_location: location import_location: location
api_end_point: currency api_end_point: currencies
- model: Department - model: Department
viewset: DepartmentViewSet viewset: DepartmentViewSet
import_location: other_core import_location: other_core
api_end_point: other/department api_end_point: departments
- model: Specialty - model: Specialty
viewset: SpecialtyViewSet viewset: SpecialtyViewSet
import_location: other_core import_location: other_core
api_end_point: other/specialty api_end_point: specialties
- model: Semester - model: Semester
viewset: SemesterViewSet viewset: SemesterViewSet
import_location: other_core import_location: other_core
api_end_point: other/semester api_end_point: semesters
- model: Offer - model: Offer
viewset: OfferViewSet viewset: OfferViewSet
import_location: other_core import_location: other_core
api_end_point: other/offer api_end_point: offers
- model: CountryTaggedItem
viewset: CountryTaggedItemViewSet
import_location: location
api_end_point: countriesTaggedItems
versionned: true
- model: CountryScholarship - model: CountryScholarship
viewset: CountryScholarshipViewSet viewset: CountryScholarshipViewSet
import_location: location import_location: location
api_end_point: country_more/scholarship api_end_point: countriesScholarships
versionned: true versionned: true
- model: CountryDri - model: CountryDri
viewset: CountryDriViewSet viewset: CountryDriViewSet
import_location: location import_location: location
api_end_point: country_more/dri api_end_point: countriesDri
versionned: true versionned: true
- model: University
viewset: UniversityViewSet
import_location: university
api_end_point: university
- model: Campus
viewset: CampusViewSet - model: CityTaggedItem
import_location: university viewset: CityTaggedItemViewSet
api_end_point: campus import_location: location
api_end_point: citiesTaggedItems
versionned: true versionned: true
- model: null
viewset: MainCampusViewSet
- model: UniversityTaggedItem
viewset: UniversityTaggedItemViewSet
import_location: university import_location: university
api_end_point: main_campus api_end_point: universitiesTaggedItems
read_only: true versionned: true
- model: UniversityScholarship - model: UniversityScholarship
viewset: UniversityScholarshipViewSet viewset: UniversityScholarshipViewSet
import_location: university import_location: university
api_end_point: university_more/scholarship api_end_point: universitiesScholarships
versionned: true versionned: true
- model: UniversityInfo - model: UniversityInfo
viewset: UniversityInfoViewSet viewset: UniversityInfoViewSet
import_location: university import_location: university
api_end_point: university_more/info api_end_point: universitiesInfo
versionned: true versionned: true
- model: UniversitySemestersDates - model: UniversitySemestersDates
viewset: UniversitySemestersDatesViewSet viewset: UniversitySemestersDatesViewSet
import_location: university import_location: university
api_end_point: university_more/semesters_dates api_end_point: universitiesSemestersDates
versionned: true versionned: true
- model: UniversityDri - model: UniversityDri
viewset: UniversityDriViewSet viewset: UniversityDriViewSet
import_location: university import_location: university
api_end_point: university_more/dri api_end_point: universitiesDri
versionned: true versionned: true
- model: null - model: null
viewset: UniversityModulesViewSet viewset: UniversityModulesViewSet
import_location: university import_location: university
api_end_point: university_more/all api_end_point: universitiesAll
api_attr: (?P<univ_id>[0-9]+) api_attr: (?P<univ_id>[0-9]+)
api_name: university_details api_name: university_details
- model: CampusTaggedItem
viewset: CampusTaggedItemViewSet
import_location: university
api_end_point: campusesTaggedItems
versionned: true
- model: null
viewset: MainCampusViewSet
import_location: university
api_end_point: mainCampuses
read_only: true
- model: Recommendation - model: Recommendation
viewset: RecommendationViewSet viewset: RecommendationViewSet
import_location: user import_location: user
api_end_point: user/recommendation api_end_point: userRecommendations
- model: RecommendationList - model: RecommendationList
viewset: RecommendationListViewSet viewset: RecommendationListViewSet
import_location: user import_location: user
api_end_point: user/recommendations_list api_end_point: userRecommendationLists
- model: PreviousDeparture - model: PreviousDeparture
viewset: PreviousDepartureViewSet viewset: PreviousDepartureViewSet
import_location: user import_location: user
api_end_point: university_more/previous_departure api_end_point: universitiesPreviousDepartures
- model: PreviousDepartureFeedback - model: PreviousDepartureFeedback
viewset: PreviousDepartureFeedbackViewSet viewset: PreviousDepartureFeedbackViewSet
import_location: user import_location: user
api_end_point: university_more/previous_departure_feedback api_end_point: universitiesPreviousDepartureFeedback
- model: UserData
viewset: UserDataViewSet
import_location: user
api_end_point: user/data
api_name: user-data-detail
- model: PendingModeration - model: PendingModeration
viewset: PendingModerationViewSet viewset: PendingModerationViewSet
import_location: my_model import_location: my_model
api_end_point: pending_moderation api_end_point: pendingModeration
- model: Version - model: Version
viewset: VersionViewSet viewset: VersionViewSet
import_location: my_model import_location: my_model
api_end_point: version api_end_point: versions
api_attr: (?P<content_type_id>[0-9]+)/(?P<object_pk>[0-9A-Za-z]+) api_attr: (?P<content_type_id>[0-9]+)/(?P<object_pk>[0-9A-Za-z]+)
api_name: versions-list api_name: versionsList
ignore_in_admin: true ignore_in_admin: true
- model: ForTestingModeration - model: ForTestingModeration
......
##### #####
# This python file is used to generate js files for redux # This python file is used to generate js files for redux
import os import os
from os.path import join
from django import template from django import template
import re import re
import yaml
############ ############
# Need to do this first so that Django template engine is working # Need to do this first so that Django template engine is working
...@@ -35,21 +37,21 @@ templates = [ ...@@ -35,21 +37,21 @@ templates = [
'combinedReducers' 'combinedReducers'
] ]
API_BASE = "http://127.0.0.1:8000/api/" API_BASE = "/api/"
with open(join(current_dir, '../../backend/generate/api_config.yml'), 'r') as f:
contexts = [ data = f.read()
{ api_config = yaml.load(data)
'name': 'universities',
'api_url': API_BASE + "university/", contexts = []
}, { for api in api_config:
'name': 'countries', if "requires_testing" in api and api["requires_testing"]:
'api_url': API_BASE + "country/" continue
}, { name = api['viewset'].split('ViewSet')[0]
'name': 'mainCampus', name = name[0].lower() + name[1:]
'api_url': API_BASE + "main_campus/", contexts.append({
'read_only': True "name": api["api_end_point"],
} "api_end_point": API_BASE + api["api_end_point"] + '/',
] })
def read_file(file): def read_file(file):
......
...@@ -29,25 +29,25 @@ import { ...@@ -29,25 +29,25 @@ import {
////////////////////////////////// //////////////////////////////////
// generic function definitions // generic function definitions
function _FetchData(pk, api_url, _IsLoading, _FetchDataSuccess, _Invalidated, _HasError, pk_required=false) { function _FetchData(pk, api_end_point, _IsLoading, _FetchDataSuccess, _Invalidated, _HasError, pk_required=false) {
if (pk_required && pk == ""){ if (pk_required && pk == ""){
throw "pk shouldn't be empty when requesting a specific element"; throw "pk shouldn't be empty when requesting a specific element";
} }
return (dispatch) => { return (dispatch) => {
dispatch(_IsLoading(true)); dispatch(_IsLoading(true));
let token = Cookies.get('csrftoken');
fetch(api_url) fetch(api_end_point, {credentials: 'same-origin',headers: {'X-CSRFToken': token}})
.then((response) => { .then((response) => {
if (!response.ok) { if (!response.ok) {
throw Error(response.statusText); throw Error(response.statusText);
} }
dispatch(_IsLoading(false));
return response; return response;
}) })
.then((response) => response.json()) .then((response) => response.json())
.then((obj) => { .then((obj) => {
dispatch(_Invalidated(false)); dispatch(_Invalidated(false));
dispatch(_FetchDataSuccess(obj)); dispatch(_FetchDataSuccess(obj));
dispatch(_IsLoading(false));
}) })
.catch(() => dispatch(_HasError(true))); .catch(() => dispatch(_HasError(true)));
}; };
...@@ -55,7 +55,7 @@ function _FetchData(pk, api_url, _IsLoading, _FetchDataSuccess, _Invalidated, _H ...@@ -55,7 +55,7 @@ function _FetchData(pk, api_url, _IsLoading, _FetchDataSuccess, _Invalidated, _H
function _ElSaveData(data, api_url, _IsLoading, _FetchDataSuccess, _Invalidated, _HasError) { function _ElSaveData(data, api_end_point, _IsLoading, _FetchDataSuccess, _Invalidated, _HasError) {
return (dispatch) => { return (dispatch) => {
let method = "POST"; let method = "POST";
let pk = ""; let pk = "";
...@@ -66,7 +66,7 @@ function _ElSaveData(data, api_url, _IsLoading, _FetchDataSuccess, _Invalidated, ...@@ -66,7 +66,7 @@ function _ElSaveData(data, api_url, _IsLoading, _FetchDataSuccess, _Invalidated,
dispatch(_ElIsSaving(true)); dispatch(_ElIsSaving(true));
let token = Cookies.get('csrftoken'); let token = Cookies.get('csrftoken');
fetch(api_url+pk, { fetch(api_end_point+pk, {
method: method, method: method,
credentials: 'same-origin', credentials: 'same-origin',
headers: { headers: {
...@@ -81,13 +81,13 @@ function _ElSaveData(data, api_url, _IsLoading, _FetchDataSuccess, _Invalidated, ...@@ -81,13 +81,13 @@ function _ElSaveData(data, api_url, _IsLoading, _FetchDataSuccess, _Invalidated,
throw Error(response.statusText); throw Error(response.statusText);
} }
dispatch(_ElIsSaving(false));
return response; return response;
}) })
.then((response) => response.json()) .then((response) => response.json())
.then((_El) => { .then((_El) => {
dispatch(_ElInvalidated(false)); dispatch(_ElInvalidated(false));
dispatch(_ElSaveDataSuccess(_El)); dispatch(_ElSaveDataSuccess(_El));
dispatch(_ElIsSaving(false));
}) })
.catch(() => dispatch(_ElHasError(true))); .catch(() => dispatch(_ElHasError(true)));
}; };
...@@ -131,7 +131,7 @@ export function {{obj.name}}FetchDataSuccess({{obj.name}}) { ...@@ -131,7 +131,7 @@ export function {{obj.name}}FetchDataSuccess({{obj.name}}) {
export function {{obj.name}}FetchData() { export function {{obj.name}}FetchData() {
return _FetchData( return _FetchData(
"", "",
"{{obj.api_url}}", "{{obj.api_end_point}}",
{{obj.name}}IsLoading, {{obj.name}}IsLoading,
{{obj.name}}FetchDataSuccess, {{obj.name}}FetchDataSuccess,
{{obj.name}}Invalidated, {{obj.name}}Invalidated,
...@@ -176,7 +176,7 @@ export function {{obj.name}}ElFetchDataSuccess({{obj.name}}El) { ...@@ -176,7 +176,7 @@ export function {{obj.name}}ElFetchDataSuccess({{obj.name}}El) {
export function {{obj.name}}ElFetchData(pk) { export function {{obj.name}}ElFetchData(pk) {
return _FetchData( return _FetchData(
pk, pk,
"{{obj.api_url}}", "{{obj.api_end_point}}",
{{obj.name}}ElIsLoading, {{obj.name}}ElIsLoading,
{{obj.name}}ElFetchDataSuccess, {{obj.name}}ElFetchDataSuccess,
{{obj.name}}ElInvalidated, {{obj.name}}ElInvalidated,
...@@ -207,7 +207,7 @@ export function {{obj.name}}ElSaveDataSuccess({{obj.name}}El) { ...@@ -207,7 +207,7 @@ export function {{obj.name}}ElSaveDataSuccess({{obj.name}}El) {
} }
export function {{obj.name}}ElSaveData(data) { export function {{obj.name}}ElSaveData(data) {
return _ElSaveData(data, "{{obj.api_url}}", {{obj.name}}ElIsLoading, {{obj.name}}ElFetchDataSuccess, {{obj.name}}ElInvalidated, {{obj.name}}ElHasError) return _ElSaveData(data, "{{obj.api_end_point}}", {{obj.name}}ElIsLoading, {{obj.name}}ElFetchDataSuccess, {{obj.name}}ElInvalidated, {{obj.name}}ElHasError)
} }
{% endif %} {% endif %}
......
...@@ -65,11 +65,11 @@ export function {{obj.name}}ElIsLoading(state = false, action) { ...@@ -65,11 +65,11 @@ export function {{obj.name}}ElIsLoading(state = false, action) {
} }
} }
export function {{obj.name}}Fetched(state = { {{obj.name}}: [], {{obj.name}}FetchedAt: null }, action) { export function {{obj.name}}Fetched(state = { data: Object(), fetchedAt: null }, action) {
switch (action.type) { switch (action.type) {
case {{obj.NAME}}_FETCH_DATA_SUCCESS: case {{obj.NAME}}_FETCH_DATA_SUCCESS:
return { return {
{{obj.name}}: action.{{obj.name}}, data: action.{{obj.name}},
fetchedAt: action.{{obj.name}}FetchedAt fetchedAt: action.{{obj.name}}FetchedAt
} }
...@@ -100,11 +100,11 @@ export function {{obj.name}}ElInvalidated(state = false, action) { ...@@ -100,11 +100,11 @@ export function {{obj.name}}ElInvalidated(state = false, action) {
} }
} }
export function {{obj.name}}ElFetched(state = { {{obj.name}}El: [], {{obj.name}}ElFetchedAt: null }, action) { export function {{obj.name}}ElFetched(state = { data: Object(), fetchedAt: null }, action) {
switch (action.type) { switch (action.type) {
case {{obj.NAME}}_EL_FETCH_DATA_SUCCESS: case {{obj.NAME}}_EL_FETCH_DATA_SUCCESS:
return { return {
{{obj.name}}El: action.{{obj.name}}El, data: action.{{obj.name}}El,
fetchedAt: action.{{obj.name}}ElFetchedAt fetchedAt: action.{{obj.name}}ElFetchedAt
} }
...@@ -128,11 +128,11 @@ export function {{obj.name}}ElIsSaving(state = false, action) { ...@@ -128,11 +128,11 @@ export function {{obj.name}}ElIsSaving(state = false, action) {
} }
} }
export function {{obj.name}}ElSaved(state = { {{obj.name}}El: [], {{obj.name}}ElSavedAt: null }, action) { export function {{obj.name}}ElSaved(state = { data: Object(), savedAt: null }, action) {
switch (action.type) { switch (action.type) {
case {{obj.NAME}}_EL_SAVING_DATA_SUCCESS: case {{obj.NAME}}_EL_SAVING_DATA_SUCCESS:
return { return {
{{obj.name}}El: action.{{obj.name}}El, data: action.{{obj.name}}El,
fetchedAt: action.{{obj.name}}ElSavedAt fetchedAt: action.{{obj.name}}ElSavedAt
} }
......
...@@ -17,7 +17,7 @@ import SchoolIcon from '@material-ui/icons/School'; ...@@ -17,7 +17,7 @@ import SchoolIcon from '@material-ui/icons/School';
import { mainListItems, secondaryListItems } from './template/listItems'; import { mainListItems, secondaryListItems } from './template/listItems';
import { connect } from "react-redux"; import { connect } from "react-redux";
import Loading from './other/Loading'; import MyComponent from './MyComponent'
// import route Components here // import route Components here
...@@ -97,10 +97,10 @@ const styles = theme => ({ ...@@ -97,10 +97,10 @@ const styles = theme => ({
myPaper: { myPaper: {
padding: 16 padding: 16
}, },
null:{} null: {}
}); });
class App extends React.Component { class App extends MyComponent {
state = { state = {
open: true, open: true,
}; };
...@@ -113,32 +113,8 @@ class App extends React.Component { ...@@ -113,32 +113,8 @@ class App extends React.Component {
this.setState({ open: false }); this.setState({ open: false });
}; };
componentDidMount() { myRender() {
if (this.props.countries.fetched.countries.length == 0 || this.props.invalidated) {
this.props.fetchData();
}
}