mirror of
https://github.com/UniversityOfHelsinkiCS/oodikone.git
synced 2026-10-12 19:03:39 +03:00
Merge pull request #1061 from UniversityOfHelsinkiCS/trunk
Student home_country to db, CLI works and other lies
This commit is contained in:
@@ -110,8 +110,10 @@ reset_real_db () {
|
||||
docker-compose up -d db user_db
|
||||
ping_psql "oodi_db" "tkt_oodi_real"
|
||||
docker exec -u postgres oodi_db dropdb "tkt_oodi_real"
|
||||
docker exec -u postgres oodi_db psql -c "CREATE DATABASE tkt_oodi_real"
|
||||
ping_psql "oodi_user_db" "user_db_real"
|
||||
docker exec -u postgres oodi_user_db dropdb "user_db_real"
|
||||
docker exec -u postgres oodi_user_db psql -c "CREATE DATABASE user_db_real"
|
||||
db_setup_full
|
||||
docker-compose down
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ const StudyrightService = require('../services/studyrights')
|
||||
// POST instead of GET because of too long params and "sensitive" data
|
||||
router.post('/v2/populationstatistics/courses', async (req, res) => {
|
||||
try {
|
||||
if (!req.body.year || !req.body.semesters || !req.body.studyRights) {
|
||||
if (!req.body.startYear || !req.body.semesters || !req.body.studyRights) {
|
||||
res.status(400).json({ error: 'The body should have a year, semester and study rights defined' })
|
||||
return
|
||||
}
|
||||
@@ -32,9 +32,9 @@ router.post('/v2/populationstatistics/courses', async (req, res) => {
|
||||
})
|
||||
|
||||
router.get('/v3/populationstatistics', async (req, res) => {
|
||||
const { year, semesters, studyRights: studyRightsJSON } = req.query
|
||||
const { startYear, semesters, studyRights: studyRightsJSON } = req.query
|
||||
try {
|
||||
if (!year || !semesters || !studyRightsJSON) {
|
||||
if (!startYear || !semesters || !studyRightsJSON) {
|
||||
res.status(400).json({ error: 'The query should have a year, semester and studyRights defined' })
|
||||
return
|
||||
}
|
||||
|
||||
@@ -108,11 +108,6 @@ const formatStudentForPopulationStatistics = ({
|
||||
const dateMonthsFromNow = (date, months) => moment(date).add(months, 'months').format('YYYY-MM-DD')
|
||||
|
||||
const getStudentsIncludeCoursesBetween = async (studentnumbers, startDate, endDate, studyright, tag) => {
|
||||
const tagQuery = tag ? {
|
||||
tag_id: {
|
||||
[Op.eq]: tag
|
||||
}
|
||||
} : null
|
||||
|
||||
const creditsOfStudentOther = {
|
||||
student_studentnumber: {
|
||||
@@ -222,7 +217,6 @@ const getStudentsIncludeCoursesBetween = async (studentnumbers, startDate, endDa
|
||||
{
|
||||
model: TagStudent,
|
||||
attributes: ['id'],
|
||||
where: tagQuery,
|
||||
include: [
|
||||
{
|
||||
model: Tag,
|
||||
@@ -236,8 +230,20 @@ const getStudentsIncludeCoursesBetween = async (studentnumbers, startDate, endDa
|
||||
studentnumber: {
|
||||
[Op.in]: studentnumbers
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
if (tag) {
|
||||
const studentsWithSearchedTag = {}
|
||||
students.forEach(student => {
|
||||
if (student.tag_students.some(t => t.tag.tag_id === tag)) {
|
||||
studentsWithSearchedTag[student.studentnumber] = true
|
||||
}
|
||||
})
|
||||
|
||||
return students.filter(student => studentsWithSearchedTag[student.studentnumber])
|
||||
}
|
||||
return students
|
||||
}
|
||||
|
||||
@@ -308,13 +314,13 @@ const studentnumbersWithAllStudyrightElements = async (studyRights, startDate, e
|
||||
}
|
||||
|
||||
const parseQueryParams = query => {
|
||||
const { semesters, studentStatuses, studyRights, months, year, tagYear } = query
|
||||
const { semesters, studentStatuses, studyRights, months, endYear, startYear } = query
|
||||
const startDate = semesters.includes('FALL') ?
|
||||
`${tagYear}-${semesterStart[semesters.find(s => s === 'FALL')]}` :
|
||||
`${moment(tagYear, 'YYYY').add(1, 'years').format('YYYY')}-${semesterStart[semesters.find(s => s === 'SPRING')]}`
|
||||
`${startYear}-${semesterStart[semesters.find(s => s === 'FALL')]}` :
|
||||
`${moment(startYear, 'YYYY').add(1, 'years').format('YYYY')}-${semesterStart[semesters.find(s => s === 'SPRING')]}`
|
||||
const endDate = semesters.includes('SPRING') ?
|
||||
`${moment(year, 'YYYY').add(1, 'years').format('YYYY')}-${semesterEnd[semesters.find(s => s === 'SPRING')]}` :
|
||||
`${year}-${semesterEnd[semesters.find(s => s === 'FALL')]}`
|
||||
`${moment(endYear, 'YYYY').add(1, 'years').format('YYYY')}-${semesterEnd[semesters.find(s => s === 'SPRING')]}` :
|
||||
`${endYear}-${semesterEnd[semesters.find(s => s === 'FALL')]}`
|
||||
const exchangeStudents = studentStatuses && studentStatuses.includes('EXCHANGE')
|
||||
const cancelledStudents = studentStatuses && studentStatuses.includes('CANCELLED')
|
||||
const nondegreeStudents = studentStatuses && studentStatuses.includes('NONDEGREE')
|
||||
@@ -422,7 +428,6 @@ const optimizedStatisticsOf = async (query) => {
|
||||
) {
|
||||
return { error: 'Student status should be either CANCELLED or EXCHANGE or NONDEGREE' }
|
||||
}
|
||||
|
||||
const {
|
||||
studyRights, startDate, months, endDate, exchangeStudents, cancelledStudents, nondegreeStudents
|
||||
} = parseQueryParams(query)
|
||||
@@ -550,7 +555,7 @@ const bottlenecksOf = async (query) => {
|
||||
|
||||
course.credits.forEach(credit => {
|
||||
const { studentnumber, passingGrade, improvedGrade, failingGrade, grade, date } = parseCreditInfo(credit)
|
||||
const semester = getPassingSemester(parseInt(query.year, 10), date)
|
||||
const semester = getPassingSemester(parseInt(query.endYear, 10), date)
|
||||
coursestats.markCredit(studentnumber, grade, passingGrade, failingGrade, improvedGrade, semester)
|
||||
})
|
||||
|
||||
|
||||
@@ -58,8 +58,8 @@ const semesters = {
|
||||
|
||||
const createQueryObject = (year, semester, codes, months) => ({
|
||||
studyRights: codes,
|
||||
year,
|
||||
tagYear: year,
|
||||
endYear: year,
|
||||
startYear: year,
|
||||
semesters: [semester],
|
||||
months
|
||||
})
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
module.exports = {
|
||||
up: async (queryInterface, Sequelize) => {
|
||||
await queryInterface.addColumn('student', 'home_country_en', { type: Sequelize.STRING })
|
||||
await queryInterface.addColumn('student', 'home_country_fi', { type: Sequelize.STRING })
|
||||
await queryInterface.addColumn('student', 'home_country_sv', { type: Sequelize.STRING })
|
||||
},
|
||||
down: async () => {
|
||||
await queryInterface.removeColumn('student', 'home_country_en')
|
||||
await queryInterface.removeColumn('student', 'home_country_fi')
|
||||
await queryInterface.removeColumn('student', 'home_country_sv')
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
module.exports = {
|
||||
up: async (queryInterface, Sequelize) => {
|
||||
await queryInterface.removeColumn('student', 'country')
|
||||
},
|
||||
down: async () => {
|
||||
await queryInterface.addColumn('student', 'country', { type: Sequelize.STRING })
|
||||
|
||||
}
|
||||
}
|
||||
@@ -193,7 +193,6 @@ const Student = sequelize.define('student',
|
||||
abbreviatedname: { type: Sequelize.STRING },
|
||||
birthdate: { type: Sequelize.DATE },
|
||||
communicationlanguage: { type: Sequelize.STRING },
|
||||
country: { type: Sequelize.STRING },
|
||||
creditcount: { type: Sequelize.INTEGER },
|
||||
dateofuniversityenrollment: { type: Sequelize.DATE },
|
||||
matriculationexamination: { type: Sequelize.STRING },
|
||||
@@ -214,6 +213,9 @@ const Student = sequelize.define('student',
|
||||
country_fi: { type: Sequelize.STRING },
|
||||
country_sv: { type: Sequelize.STRING },
|
||||
country_en: { type: Sequelize.STRING },
|
||||
home_country_fi: { type: Sequelize.STRING },
|
||||
home_country_sv: { type: Sequelize.STRING },
|
||||
home_country_en: { type: Sequelize.STRING },
|
||||
gender_code: { type: Sequelize.INTEGER },
|
||||
gender_fi: { type: Sequelize.STRING },
|
||||
gender_sv: { type: Sequelize.STRING },
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import { withRouter } from 'react-router'
|
||||
import { connect } from 'react-redux'
|
||||
import { string, func, arrayOf, shape } from 'prop-types'
|
||||
import { getFaculties } from '../../../redux/faculties'
|
||||
import { getTextIn } from '../../../common'
|
||||
import SortableTable from '../../SortableTable'
|
||||
|
||||
|
||||
|
||||
const FacultySelector = ({ language, handleSelect, dispatchGetFaculties, faculties }) => {
|
||||
const fetchFaculties = async () => {
|
||||
await dispatchGetFaculties()
|
||||
}
|
||||
useEffect(() => {
|
||||
fetchFaculties()
|
||||
}, [])
|
||||
|
||||
if (!faculties) return null
|
||||
const headers = [
|
||||
{
|
||||
key: 'name',
|
||||
title: 'name',
|
||||
getRowVal: faculty => getTextIn(faculty.name, language)
|
||||
},
|
||||
{
|
||||
key: 'code',
|
||||
title: 'code',
|
||||
getRowVal: faculty => faculty.code
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
return (
|
||||
<SortableTable
|
||||
columns={headers}
|
||||
getRowKey={faculty => faculty.code}
|
||||
getRowProps={faculty => ({ onClick: () => handleSelect(faculty.code), style: { cursor: 'pointer' } })}
|
||||
data={faculties}
|
||||
/>
|
||||
)
|
||||
}
|
||||
FacultySelector.propTypes = {
|
||||
language: string.isRequired,
|
||||
handleSelect: func.isRequired,
|
||||
dispatchGetFaculties: func.isRequired,
|
||||
faculties: arrayOf(shape({})).isRequired
|
||||
}
|
||||
|
||||
const mapStateToProps = ({ faculties, settings }) => ({
|
||||
faculties: faculties.data,
|
||||
language: settings.language
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps, { dispatchGetFaculties: getFaculties })(withRouter(FacultySelector))
|
||||
@@ -0,0 +1,18 @@
|
||||
import React from 'react'
|
||||
import { withRouter } from 'react-router'
|
||||
import { Header, Segment } from 'semantic-ui-react'
|
||||
import FacultySelector from './FacultySelector'
|
||||
|
||||
const Faculty = () => (
|
||||
<div className="segmentContainer">
|
||||
<Header className="segmentTitle" size="large">
|
||||
Faculties
|
||||
</Header>
|
||||
<Segment className="contentSegment" >
|
||||
<FacultySelector />
|
||||
</Segment>
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
export default withRouter(Faculty)
|
||||
@@ -191,12 +191,11 @@ class PopulationCourseStats extends Component {
|
||||
clearCourseStats: clearCourseStatsfn,
|
||||
years
|
||||
} = this.props
|
||||
|
||||
const yearCode = year => Object.values(years).find(yearObject =>
|
||||
yearObject.yearname.slice(0, 4).includes(year)).yearcode
|
||||
const { year, months } = query
|
||||
const fromYear = yearCode(year)
|
||||
const toYear = yearCode(moment(moment(year, 'YYYY').add(months, 'months')).format('YYYY'))
|
||||
const { startYear, months } = query
|
||||
const fromYear = yearCode(startYear)
|
||||
const toYear = yearCode(moment(moment(startYear, 'YYYY').add(months, 'months')).format('YYYY'))
|
||||
history.push('/coursestatistics/')
|
||||
clearCourseStatsfn()
|
||||
getStatsFn({
|
||||
|
||||
@@ -23,7 +23,7 @@ const PopulationQueryCard =
|
||||
history.push('/populations')
|
||||
removeSampleFn(uuid)
|
||||
}
|
||||
const { uuid, year, semesters, months, studentStatuses } = query
|
||||
const { uuid, startYear, semesters, months, studentStatuses } = query
|
||||
const { students } = population
|
||||
if (students.length > 0) {
|
||||
return (
|
||||
@@ -40,7 +40,7 @@ const PopulationQueryCard =
|
||||
<div className="dateItem">
|
||||
<Icon name="calendar" size="small" />
|
||||
{`${semesters.map(s => translate(`populationStatistics.${s}`))}/
|
||||
${year}-${Number(year) + 1}, showing ${months} months.`}
|
||||
${startYear}-${Number(startYear) + 1}, showing ${months} months.`}
|
||||
</div>
|
||||
<div>
|
||||
{`${translate('populationStatistics.sampleSize', { amount: students.length })} `}
|
||||
@@ -48,11 +48,11 @@ const PopulationQueryCard =
|
||||
<div>
|
||||
{`Updated at ${reformatDate(_.minBy(students, 'updatedAt').updatedAt, DISPLAY_DATE_FORMAT)} `}
|
||||
</div>
|
||||
<div>{studentStatuses.includes('EXCHANGE') ? 'Includes' : 'Excludes' } exchange students</div>
|
||||
<div>{studentStatuses.includes('CANCELLED') ? 'Includes ' : 'Excludes ' }
|
||||
<div>{studentStatuses.includes('EXCHANGE') ? 'Includes' : 'Excludes'} exchange students</div>
|
||||
<div>{studentStatuses.includes('CANCELLED') ? 'Includes ' : 'Excludes '}
|
||||
students with cancelled study right
|
||||
</div>
|
||||
<div>{studentStatuses.includes('NONDEGREE') ? 'Includes ' : 'Excludes ' }
|
||||
<div>{studentStatuses.includes('NONDEGREE') ? 'Includes ' : 'Excludes '}
|
||||
students with non-degree study right
|
||||
</div>
|
||||
{updating ?
|
||||
@@ -83,7 +83,7 @@ const PopulationQueryCard =
|
||||
<Card.Meta>
|
||||
<div className="dateItem">
|
||||
<Icon name="calendar" size="small" />
|
||||
{`${semesters.map(s => translate(`populationStatistics.${s}`))}/${year}-${Number(year) + 1},
|
||||
{`${semesters.map(s => translate(`populationStatistics.${s}`))}/${startYear}-${Number(startYear) + 1},
|
||||
showing ${months} months.`}
|
||||
</div>
|
||||
<div>
|
||||
@@ -109,7 +109,7 @@ PopulationQueryCard.propTypes = {
|
||||
translate: func.isRequired,
|
||||
population: shape({ students: arrayOf(object), extents: arrayOf(object) }).isRequired,
|
||||
query: shape({
|
||||
year: oneOfType([string, number]),
|
||||
startYear: oneOfType([string, number]),
|
||||
semester: string,
|
||||
studyRights: shape({ programme: string, degree: string, studyTrack: string }),
|
||||
uuid: string
|
||||
|
||||
@@ -120,7 +120,6 @@ class PopulationSearchForm extends Component {
|
||||
const query = {
|
||||
...initial,
|
||||
...rest,
|
||||
tagYear: rest.year,
|
||||
studyRights: JSON.parse(studyRights),
|
||||
months: JSON.parse(months)
|
||||
}
|
||||
@@ -162,7 +161,6 @@ class PopulationSearchForm extends Component {
|
||||
handleYearSelection = (momentYear) => {
|
||||
const { query } = this.state
|
||||
const { studyProgrammes } = this.props
|
||||
|
||||
if (!moment.isMoment(momentYear)) {
|
||||
this.setState({
|
||||
momentYear: null,
|
||||
@@ -200,13 +198,12 @@ class PopulationSearchForm extends Component {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
momentYear,
|
||||
query: {
|
||||
...query,
|
||||
year: reformatDate(momentYear, YEAR_DATE_FORMAT),
|
||||
tagYear: reformatDate(momentYear, YEAR_DATE_FORMAT),
|
||||
endYear: reformatDate(momentYear, YEAR_DATE_FORMAT),
|
||||
startYear: reformatDate(momentYear, YEAR_DATE_FORMAT),
|
||||
months: this.months(
|
||||
reformatDate(momentYear, YEAR_DATE_FORMAT),
|
||||
this.state.query.semesters.includes('FALL') ? 'FALL' : 'SPRING'
|
||||
@@ -221,28 +218,33 @@ class PopulationSearchForm extends Component {
|
||||
}
|
||||
|
||||
handleTagSearch = (event, { value }) => {
|
||||
const { query } = this.state
|
||||
const months = this.getMonths('2015', new Date(), 'FALL')
|
||||
this.setState({
|
||||
query: {
|
||||
...query,
|
||||
year: '2018',
|
||||
tagYear: '2015',
|
||||
months
|
||||
},
|
||||
selectedTag: value
|
||||
})
|
||||
}
|
||||
|
||||
handleTagYearSelect = (momentYear) => {
|
||||
const { query } = this.state
|
||||
const months = this.getMonths(reformatDate(momentYear, YEAR_DATE_FORMAT), new Date(), 'FALL')
|
||||
this.setState({
|
||||
query: {
|
||||
...query,
|
||||
startYear: reformatDate(momentYear, YEAR_DATE_FORMAT),
|
||||
endYear: reformatDate(new Date(), YEAR_DATE_FORMAT),
|
||||
months
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
addYear = () => {
|
||||
const { year } = this.state.query
|
||||
const nextYear = momentFromFormat(year, YEAR_DATE_FORMAT).add(1, 'year')
|
||||
const { startYear } = this.state.query
|
||||
const nextYear = momentFromFormat(startYear, YEAR_DATE_FORMAT).add(1, 'year')
|
||||
this.handleYearSelection(nextYear)
|
||||
}
|
||||
|
||||
subtractYear = () => {
|
||||
const { year } = this.state.query
|
||||
const previousYear = momentFromFormat(year, YEAR_DATE_FORMAT).subtract(1, 'year')
|
||||
const { startYear } = this.state.query
|
||||
const previousYear = momentFromFormat(startYear, YEAR_DATE_FORMAT).subtract(1, 'year')
|
||||
this.handleYearSelection(previousYear)
|
||||
}
|
||||
|
||||
@@ -254,7 +256,7 @@ class PopulationSearchForm extends Component {
|
||||
query: {
|
||||
...query,
|
||||
semesters,
|
||||
months: this.months(this.state.query.year, semesters.includes('FALL') ? 'FALL' : 'SPRING')
|
||||
months: this.months(this.state.query.startYear, semesters.includes('FALL') ? 'FALL' : 'SPRING')
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -327,7 +329,7 @@ class PopulationSearchForm extends Component {
|
||||
|
||||
handleMonthsChange = (value) => {
|
||||
const { query } = this.state
|
||||
const months = this.getMonths(query.year, value, this.state.query.semesters.includes('FALL') ? 'FALL' : 'SPRING')
|
||||
const months = this.getMonths(query.startYear, value, this.state.query.semesters.includes('FALL') ? 'FALL' : 'SPRING')
|
||||
this.setState({
|
||||
query: {
|
||||
...query,
|
||||
@@ -349,17 +351,17 @@ class PopulationSearchForm extends Component {
|
||||
})
|
||||
}
|
||||
|
||||
getMonths = (year, end, term) => {
|
||||
getMonths = (startYear, end, term) => {
|
||||
const lastDayOfMonth = moment(end).endOf('month')
|
||||
const start = term === 'FALL' ? `${year}-08-01` : `${year}-01-01`
|
||||
const start = term === 'FALL' ? `${startYear}-08-01` : `${startYear}-01-01`
|
||||
this.setState({
|
||||
floatMonths: moment.duration(moment(lastDayOfMonth).diff(moment(start))).asMonths()
|
||||
})
|
||||
return Math.round(moment.duration(moment(lastDayOfMonth).diff(moment(start))).asMonths())
|
||||
}
|
||||
|
||||
getMonthValue = (year, months) => {
|
||||
const start = `${year}-08-01`
|
||||
getMonthValue = (startYear, months) => {
|
||||
const start = `${startYear}-08-01`
|
||||
return moment(start).add(months - 1, 'months').format('MMMM YY')
|
||||
}
|
||||
|
||||
@@ -373,7 +375,7 @@ class PopulationSearchForm extends Component {
|
||||
return this.props.studyProgrammes[this.state.query.studyRights.programme].enrollmentStartYears[momentYear.year()] != null
|
||||
}
|
||||
|
||||
getMinSelection = (year, semester) => (semester === 'FALL' ? `${year}-08-01` : `${year}-01-01`)
|
||||
getMinSelection = (startYear, semester) => (semester === 'FALL' ? `${startYear}-08-01` : `${startYear}-01-01`)
|
||||
|
||||
fetchPopulationFromUrlParams() {
|
||||
const query = this.parseQueryFromUrl()
|
||||
@@ -382,8 +384,8 @@ class PopulationSearchForm extends Component {
|
||||
}
|
||||
|
||||
initialQuery = () => ({
|
||||
year: Datetime.moment('2017-01-01').year(),
|
||||
tagYear: Datetime.moment('2017-01-01').year(),
|
||||
endYear: Datetime.moment('2017-01-01').year(),
|
||||
startYear: Datetime.moment('2017-01-01').year(),
|
||||
semesters: ['FALL', 'SPRING'],
|
||||
studentStatuses: [],
|
||||
studyRights: [],
|
||||
@@ -404,7 +406,7 @@ class PopulationSearchForm extends Component {
|
||||
|
||||
renderEnrollmentDateSelector = () => {
|
||||
const { query, momentYear } = this.state
|
||||
const { semesters, year } = query
|
||||
const { semesters, startYear } = query
|
||||
return (
|
||||
<Form.Group key="year" className="enrollmentSelectorGroup">
|
||||
<Form.Field error={!this.validYearCheck(momentYear)} className="yearSelect">
|
||||
@@ -416,7 +418,7 @@ class PopulationSearchForm extends Component {
|
||||
timeFormat={false}
|
||||
renderYear={(props, selectableYear) => <td {...props}>{`${selectableYear}-${selectableYear + 1}`}</td>}
|
||||
closeOnSelect
|
||||
value={`${year}-${moment().year(year).add(1, 'years').format('YYYY')}`}
|
||||
value={`${startYear}-${moment().year(startYear).add(1, 'years').format('YYYY')}`}
|
||||
isValidDate={this.validYearCheck}
|
||||
onChange={this.handleYearSelection}
|
||||
/>
|
||||
@@ -431,10 +433,10 @@ class PopulationSearchForm extends Component {
|
||||
<label>Statistics until</label>
|
||||
<Datetime
|
||||
dateFormat="MMMM YYYY"
|
||||
defaultValue={this.getMonthValue(this.state.query.year, this.state.floatMonths)}
|
||||
defaultValue={this.getMonthValue(this.state.query.startYear, this.state.floatMonths)}
|
||||
onChange={value => this.handleMonthsChange(value)}
|
||||
isValidDate={current => current.isBefore(moment()) &&
|
||||
current.isAfter(this.getMinSelection(year, semesters[1] || semesters[0]))}
|
||||
current.isAfter(this.getMinSelection(startYear, semesters[1] || semesters[0]))}
|
||||
/>
|
||||
</Form.Field>
|
||||
</Form.Group>
|
||||
@@ -562,7 +564,7 @@ class PopulationSearchForm extends Component {
|
||||
|
||||
const { translate, tags } = this.props
|
||||
const { query } = this.state
|
||||
const { semesters, studentStatuses } = query
|
||||
const { semesters, studentStatuses, startYear } = query
|
||||
const options = this.state.isAdmin ? tags.map(tag => ({ key: tag.tag_id, text: tag.tagname, value: tag.tag_id })) : null
|
||||
|
||||
return (
|
||||
@@ -629,6 +631,17 @@ class PopulationSearchForm extends Component {
|
||||
options={options}
|
||||
onChange={this.handleTagSearch}
|
||||
/>
|
||||
<Datetime
|
||||
className="yearSelectInput"
|
||||
control={Datetime}
|
||||
dateFormat={YEAR_DATE_FORMAT}
|
||||
timeFormat={false}
|
||||
renderYear={(props, selectableYear) => <td {...props}>{`${selectableYear}-${selectableYear + 1}`}</td>}
|
||||
closeOnSelect
|
||||
value={`${startYear}-${moment().year(startYear).add(1, 'years').format('YYYY')}`}
|
||||
isValidDate={this.validYearCheck}
|
||||
onChange={this.handleTagYearSelect}
|
||||
/>
|
||||
<Button onClick={() => this.fetchPopulation(this.state.query, this.state.selectedTag)}> Search by tag</Button>
|
||||
</div>) : null}
|
||||
</Form.Field>
|
||||
|
||||
@@ -15,6 +15,7 @@ const Sandbox = React.lazy(() => import('../Sandbox'))
|
||||
const UsageStatistics = React.lazy(() => import('../UsageStatistics'))
|
||||
const OodiLearn = React.lazy(() => import('../OodiLearn'))
|
||||
const Feedback = React.lazy(() => import('../Feedback'))
|
||||
const Faculty = React.lazy(() => import('../Faculty'))
|
||||
|
||||
const Routes = () => (
|
||||
<Suspense fallback={<Loader active inline="centered" />}>
|
||||
@@ -25,6 +26,7 @@ const Routes = () => (
|
||||
<Route exact path="/study-programme/:studyProgrammeId/course-group/:courseGroupId" component={StudyProgramme} />
|
||||
<Route exact path={routes.students.route} component={StudentStatistics} />
|
||||
<Route exact path={routes.courseStatistics.route} component={CourseStatistics} />
|
||||
<Route exact path={routes.faculty.route} component={Faculty} />
|
||||
<Route exact path={routes.settings.route} component={Settings} />
|
||||
<Route exact path={routes.users.route} component={EnableUsers} />
|
||||
<Route exact path={routes.teachers.route} component={Teachers} />
|
||||
|
||||
@@ -22,7 +22,7 @@ const ThroughputTable = ({ history, throughput, thesis, loading, error, studypro
|
||||
const year = Number(yearLabel.slice(0, 4))
|
||||
const months = Math.ceil(moment.duration(moment().diff(`${year}-08-01`)).asMonths())
|
||||
history.push(`/populations?months=${months}&semesters=FALL&semesters=` +
|
||||
`SPRING&studyRights=%7B"programme"%3A"${studyprogramme}"%7D&year=${year}`)
|
||||
`SPRING&studyRights=%7B"programme"%3A"${studyprogramme}"%7D&startYear=${year}&endYear=${year}`)
|
||||
}
|
||||
if (error) return <h1>Oh no so error {error}</h1>
|
||||
let GRADUATED_FEATURE_TOGGLED_ON = false
|
||||
|
||||
@@ -59,6 +59,7 @@ export const routes = {
|
||||
courseStatistics: { menuRoute: '/coursestatistics', route: '/coursestatistics', translateId: 'courseStatistics' },
|
||||
teachers: { menuRoute: '/teachers', route: '/teachers/:teacherid?', translateId: 'teachers', reqRights: ['teachers'] },
|
||||
users: { menuRoute: '/users', route: '/users/:userid?', translateId: 'users', reqRights: ['users'] },
|
||||
faculty: { menuRoute: '/faculties', route: '/faculties/:facultyid?', translateId: 'faculty', reqRights: ['dev'] },
|
||||
settings: { menuRoute: '/settings', route: '/settings', translateId: 'settings', reqRights: ['dev'] },
|
||||
usage: { menuRoute: '/usage', route: '/usage', translateId: 'usage', reqRights: ['usage'] },
|
||||
sandbox: { menuRoute: '/sandbox', route: '/sandbox', translateId: 'sandbox', reqRights: ['dev'] },
|
||||
|
||||
@@ -90,6 +90,9 @@
|
||||
"courseGroups": [
|
||||
"Course groups"
|
||||
],
|
||||
"faculty": [
|
||||
"Faculty"
|
||||
],
|
||||
"class": [
|
||||
"Search by class"
|
||||
],
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import { callController } from '../apiConnection'
|
||||
|
||||
export const getPopulationCourses = ({
|
||||
year, semesters, studentStatuses, studyRights, months, uuid, selectedStudents, tagYear
|
||||
endYear, semesters, studentStatuses, studyRights, months, uuid, selectedStudents, startYear
|
||||
}) => {
|
||||
const route = '/v2/populationstatistics/courses'
|
||||
const prefix = 'GET_POPULATION_COURSES_'
|
||||
const query = {
|
||||
year, semesters, studentStatuses, studyRights, uuid, selectedStudents, months, tagYear
|
||||
endYear, semesters, studentStatuses, studyRights, uuid, selectedStudents, months, startYear
|
||||
}
|
||||
const body = {
|
||||
year,
|
||||
endYear,
|
||||
semesters,
|
||||
studentStatuses,
|
||||
months,
|
||||
studyRights,
|
||||
selectedStudents,
|
||||
tagYear
|
||||
startYear
|
||||
}
|
||||
return callController(route, prefix, body, 'post', query)
|
||||
}
|
||||
|
||||
@@ -9,21 +9,21 @@ const initialState = {
|
||||
}
|
||||
|
||||
export const getPopulationStatistics = ({
|
||||
year, semesters, studentStatuses, studyRights, months, uuid, tag, tagYear
|
||||
endYear, semesters, studentStatuses, studyRights, months, uuid, tag, startYear
|
||||
}) => {
|
||||
const route = '/v3/populationstatistics/'
|
||||
const prefix = 'GET_POPULATION_STATISTICS_'
|
||||
const query = {
|
||||
year, semesters, studentStatuses, studyRights, uuid, months, tag, tagYear
|
||||
endYear, semesters, studentStatuses, studyRights, uuid, months, tag, startYear
|
||||
}
|
||||
const params = {
|
||||
year,
|
||||
endYear,
|
||||
semesters,
|
||||
studentStatuses,
|
||||
months,
|
||||
studyRights,
|
||||
tag,
|
||||
tagYear
|
||||
startYear
|
||||
}
|
||||
return callController(route, prefix, null, 'get', query, params)
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ const getStudentFromData = (student, studyrights) => {
|
||||
const language = getTextsByLanguage(student.language)
|
||||
const country = getTextsByLanguage(student.country)
|
||||
const gender = getTextsByLanguage(student.gender)
|
||||
const home_country = getTextsByLanguage(student.home_country)
|
||||
return {
|
||||
studentnumber: student.student_number,
|
||||
email: student.email,
|
||||
@@ -52,6 +53,9 @@ const getStudentFromData = (student, studyrights) => {
|
||||
country_fi: country.fi,
|
||||
country_sv: country.sv,
|
||||
country_en: country.en,
|
||||
home_country_fi: home_country.fi,
|
||||
home_country_sv: home_country.sv,
|
||||
home_country_en: home_country.en,
|
||||
firstnames: student.first_names,
|
||||
communicationlanguage: language.en || language.fi || language.sv,
|
||||
dateofuniversityenrollment: universityEnrollmentDateFromStudyRights(studyrights),
|
||||
|
||||
Reference in New Issue
Block a user