Fakultas Ilmu Komputer UI

Commit a0639678 authored by Rachmat Ridwan's avatar Rachmat Ridwan
Browse files

Merge branch 'master' of https://gitlab.cs.ui.ac.id/pmpl/class-project/kape into 1606886974-179-3

parents 56bb5d89 a5d987c7
Pipeline #26857 passed with stages
in 18 minutes and 24 seconds
File added
......@@ -191,16 +191,17 @@ karyawan
key={this.state.refresh}
onSubmit={this.handleSubmit}
>
<Form.Field>
<Form.Field required>
<label htmlFor="name">Nama Perusahaan</label>
<input
placeholder="Nama Perusahaan"
name="name"
onChange={this.handleChange}
defaultValue={this.state.name === null ? null : this.state.name}
required
/>
</Form.Field>
<Form.Field>
<Form.Field required>
<label htmlFor="address">Alamat Perusahaan</label>
<input
placeholder="Alamat Perusahaan"
......@@ -209,9 +210,10 @@ karyawan
defaultValue={
this.state.address === null ? null : this.state.address
}
required
/>
</Form.Field>
<Form.Field>
<Form.Field required>
<label htmlFor="description">Deskripsi</label>
<TextArea
placeholder="Try adding multiple lines"
......@@ -223,9 +225,23 @@ karyawan
? null
: this.state.description
}
required
/>
</Form.Field>
<Form.Field>
<Form.Field required>
<label htmlFor="founded">Founded:</label>
<input
name="founded"
placeholder="YYYY-MM-DD"
pattern="\d{4}\-\d{2}\-\d{2}"
onChange={this.handleChange}
defaultValue={
this.state.founded === null ? null : this.state.founded
}
required
/>
</Form.Field>
<Form.Field required>
<label htmlFor="size">Jumlah karyawan</label>
<input
placeholder="Jumlah karyawan keseluruhan"
......@@ -235,9 +251,10 @@ karyawan
defaultValue={
this.state.size === null ? '0' : this.state.size
}
required
/>
</Form.Field>
<Form.Field>
<Form.Field required>
<label htmlFor="website">Website</label>
<input
placeholder="Alamat Website"
......@@ -246,6 +263,7 @@ karyawan
defaultValue={
this.state.website === null ? null : this.state.website
}
required
/>
</Form.Field>
<Form.Field>
......
......@@ -63,6 +63,7 @@ export default class EditProfile extends ProfileHandler {
refresh: 1,
loading: false,
linkedin_url: '',
self_description: '',
hackerrank_url: '',
student_gpa: 0.0,
student_toefl: 0,
......
This diff is collapsed.
......@@ -29,6 +29,7 @@ const studentUserVerified = {
updated: '2017-03-28T13:33:46.148248Z',
npm: 1406543593,
resume: null,
self_description: null,
phone_number: null,
sertifikat:'ada',
bookmarked_vacancies: [
......@@ -121,6 +122,7 @@ describe('ProfilePage', () => {
studentUserVerified.data.student.bookmarked_vacancies);
expect(profile.state.applied_vacancies).to.equal(
studentUserVerified.data.student.applied_vacancies);
expect(profile.state.self_description).to.equal(studentUserVerified.data.self_description);
});
})
......@@ -134,8 +136,11 @@ describe('ProfilePage', () => {
/>,
);
const phoneNumberNode = ReactTestUtils.scryRenderedDOMComponentsWithTag(profile, 'Input')[2];
profile.getProfile().then(()=> expect(
profile.state.phone_number).to.equal(phoneNumberNode.value));
const selfDescNode = ReactTestUtils.scryRenderedDOMComponentsWithTag(profile, 'Input')[4];
profile.getProfile().then(()=> {
expect(profile.state.phone_number).to.equal(phoneNumberNode.value);
expect(profile.state.self_description).to.equal(selfDescNode.value);
});
// profile.updateForm(true);
fetchMock.restore();
});
......
import React from 'react';
import ReactTestUtils from 'react-dom/test-utils';
import AdminVerificationModal from '../../components/AdminVerificationModal';
describe('AdminVerificationModal', () => {
it('renders without problem', () => {
const modalAdmin = ReactTestUtils.renderIntoDocument(
<AdminVerificationModal />,
);
expect(modalAdmin).to.exist;
});
it('close without problem', () => {
const modalAdmin = ReactTestUtils.renderIntoDocument(
<AdminVerificationModal />,
);
modalAdmin.handleClose();
expect(modalAdmin.state.modalOpen).to.equal(false);
});
it('open without problem', () => {
const modalAdmin = ReactTestUtils.renderIntoDocument(
<AdminVerificationModal />,
);
modalAdmin.handleOpen();
expect(modalAdmin.state.modalOpen).to.equal(true);
});
});
......@@ -47,6 +47,14 @@ describe('CompanyRegisterModal', () => {
expect(companyRegister.categoryOptions).to.exist;
});
it('renders recaptcha without problem', () => {
const companyRegister = ReactTestUtils.renderIntoDocument(
<CompanyRegisterModal />,
);
const recaptcha = ReactTestUtils.scryRenderedComponentsWithType(companyRegister, 'ReCAPTCHA');
expect(recaptcha).to.exist;
});
it('handle password validation', () => {
const password = '3s24Aasd';
expect(validatePassword(password)).to.equal(true);
......@@ -58,4 +66,11 @@ describe('CompanyRegisterModal', () => {
);
expect(companyRegister.state.benefits).to.exist;
});
it('Register modal state contain recaptchaValue', () => {
const companyRegister = ReactTestUtils.renderIntoDocument(
<CompanyRegisterModal />,
);
expect(companyRegister.state.recaptchaValue).to.equal(null);
});
});
......@@ -389,6 +389,17 @@ describe('VacancyList', () => {
expect(vacancyList.generateVacancies()).to.exist;
});
it('filters filled-out applications for stident user', () => {
const vacancyList = ReactTestUtils.renderIntoDocument(
<VacancyList items={newResponse} userId={3} user={studentUser} />,
);
vacancyList.state.vacancies = newResponse;
vacancyList.state.vacancyStateFilter = 3;
expect(vacancyList.generateVacancies()).to.exist;
vacancyList.state.vacancyStateFilter = 4;
expect(vacancyList.generateVacancies()).to.exist;
});
it('renders without problem for company', () => {
const vacancyList = ReactTestUtils.renderIntoDocument(
<VacancyList items={newResponse} userId={1} user={companyUser} />,
......
import React from 'react';
import ReactTestUtils from 'react-dom/test-utils';
import VerifyAdminModal from '../../components/VerifyAdminModal';
describe('VerifyAdminModal', () => {
it('renders without problem', () => {
const verifyModal = ReactTestUtils.renderIntoDocument(
<VerifyAdminModal />,
);
expect(verifyModal).to.exist;
});
it('open without problem', () => {
const verifyModal = ReactTestUtils.renderIntoDocument(
<VerifyAdminModal id={4} />,
);
const modal = ReactTestUtils.findRenderedDOMComponentWithTag(verifyModal, 'Button');
ReactTestUtils.Simulate.click(modal);
expect(verifyModal.state.modalOpen).to.equal(true);
});
it('close without problem', () => {
const verifyModal = ReactTestUtils.renderIntoDocument(
<VerifyAdminModal id={4} />,
);
verifyModal.handleClose();
expect(verifyModal.state.modalOpen).to.equal(false);
});
});
import React from 'react';
import {
Button, Header, Modal, Grid,
} from 'semantic-ui-react';
export default class AdminVerificationModal extends React.Component {
state = { modalOpen: false }
componentWillUpdate() {
this.fixBody();
}
componentDidUpdate() {
this.fixBody();
}
fixBody = () => {
const anotherModal = document.getElementsByClassName('ui page modals').length;
if (anotherModal > 0) document.body.classList.add('scrolling', 'dimmable', 'dimmed');
};
handleOpen = () => this.setState({
modalOpen: true,
});
handleClose = () => this.setState({
modalOpen: false,
});
render() {
return (
<Modal
trigger={
<Button color="blue" icon="right chevron" labelPosition="right" floated="right" content="ubah" onClick={this.handleOpen} />
}
closeIcon="close"
open={this.state.modalOpen}
onClose={this.handleClose}
>
<Modal.Header>Software Engineer</Modal.Header>
<Modal.Content>
<Modal.Description>
<Header>Deskripsi Lowongan</Header>
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat.
</Modal.Description>
</Modal.Content>
<Modal.Actions>
<Grid columns={2}>
<Grid.Column>
<Button color="red" floated="left" onClick={this.handleClose}>Hapus</Button>
</Grid.Column>
<Grid.Column>
<Button color="blue" floated="right" onClick={this.handleClose}>Ubah</Button>
<Button color="green" floated="right" onClick={this.handleClose}>Verifikasi</Button>
</Grid.Column>
</Grid>
</Modal.Actions>
</Modal>
);
}
}
......@@ -7,6 +7,7 @@ import ModalAlert from './ModalAlert';
import Server from '../lib/Server';
import Storage from '../lib/Storage';
import Dumper from '../lib/Dumper';
import ReCAPTCHA from "react-google-recaptcha";
export default class CompanyRegisterModal extends React.Component {
constructor(props) {
......@@ -19,6 +20,7 @@ export default class CompanyRegisterModal extends React.Component {
{ text: 'Mempermudah mencari calon peserta magang' },
{ text: 'Dan banyak keuntungan lainnya' },
],
recaptchaValue: null,
};
this.handleChange = this.handleChange.bind(this);
this.handleFile = this.handleFile.bind(this);
......@@ -97,16 +99,25 @@ export default class CompanyRegisterModal extends React.Component {
}
};
handleRecaptchaValue = (value) => {
this.setState({ recaptchaValue: value });
};
handleSubmit = (e) => {
e.preventDefault();
this.setState({ loading: true });
Server.submit('/register/', this.state).then((response) => {
Storage.set('user-data', response);
browserHistory.push('/home');
}, (error) => error.then((r) => {
this.setState({ loading: false });
this.modalAlert.open('Gagal Membuat Akun', Dumper.dump(r));
}));
if(this.state.recaptchaValue != null){
this.setState({ loading: true });
Server.submit('/register/', this.state).then((response) => {
Storage.set('user-data', response);
browserHistory.push('/home');
}, (error) => error.then((r) => {
this.setState({ loading: false });
this.modalAlert.open('Gagal Membuat Akun', Dumper.dump(r));
}));
}
else {
this.modalAlert.open('Pastikan anda bukan robot', Dumper.dump());
}
};
render() {
......@@ -193,6 +204,10 @@ export default class CompanyRegisterModal extends React.Component {
<label htmlFor="description">Deskripsi</label>
<TextArea onChange={this.handleChange} placeholder="Tell us more" name="description" autoHeight required />
</Form.Field>
<Form.Field required>
<label htmlFor="founded">Founded</label>
<TextArea onChange={this.handleChange} placeholder="YYYY-MM-DD" name="founded" required />
</Form.Field>
<Form.Field required>
<label htmlFor="address">Alamat</label>
<Input onChange={this.handleChange} placeholder="Alamat" name="address" required />
......@@ -205,6 +220,10 @@ export default class CompanyRegisterModal extends React.Component {
<label htmlFor="address">Website</label>
<Input onChange={this.handleChange} placeholder="Website perusahaan anda" name="website" required />
</Form.Field>
<ReCAPTCHA
sitekey="6LfUYMYUAAAAAF_Yj073qov9JOMrYQaNIu3-UIF7"
onChange={(value) => { this.handleRecaptchaValue(value); }}
/>
<Modal.Actions style={{ textAlign: 'right' }}>
<Button type="reset" color="red">
<Icon name="remove" />
......
......@@ -208,8 +208,10 @@ export default class TopMenu extends React.Component {
description={data.user.email}
/>
{ this.props.user.role === 'student' &&
<Menu.Item as={Link} to="/profil-mahasiswa" style={{ margin: '10px' }} name="Profil" active={activeItem === 'Profil'} onClick={this.handleItemClick} /> }
<Menu.Item as={Link} to="/edit-profil-mahasiswa" style={{ margin: '10px' }} name="Edit Profil" active={activeItem === 'EditProfil'} onClick={this.handleItemClick} />
<div>
<Menu.Item as={Link} to="/profil-mahasiswa" style={{ margin: '10px' }} name="Profil" active={activeItem === 'Profil'} onClick={this.handleItemClick} />
<Menu.Item as={Link} to="/edit-profil-mahasiswa" style={{ margin: '10px' }} name="Edit Profil" active={activeItem === 'EditProfil'} onClick={this.handleItemClick} />
</div>}
<Button.Group floated="right">
<Button as={Link} onClick={this.logout} loading={this.state.logoutLoading} name="logout" color="blue" size="tiny">Keluar</Button></Button.Group>
</Popup>
......
......@@ -39,6 +39,8 @@ export default class VacancyList extends React.Component {
{ key: 0, text: 'Semua', value: 0 },
{ key: 1, text: 'Masih Menerima', value: 1 },
{ key: 2, text: 'Sudah Tutup', value: 2 },
{ key: 3, text: 'Belum Terpenuhi', value: 3},
{ key: 4, text: 'Sudah Terpenuhi', value: 4},
],
sort: '',
sortBy: [
......@@ -119,6 +121,16 @@ export default class VacancyList extends React.Component {
filteredVacancies = filteredVacancies.filter(
(vacancy) => vacancy.props.data.close_time < moment().format(),
);
} else if (vacancyStateFilter === 3) {
filteredVacancies = filteredVacancies.filter(
(vacancy) => vacancy.props.data.total_accepted_applicants
< vacancy.props.data.max_accepted_applicants,
);
} else if (vacancyStateFilter === 4) {
filteredVacancies = filteredVacancies.filter(
(vacancy) => vacancy.props.data.total_accepted_applicants
>= vacancy.props.data.max_accepted_applicants,
);
}
return filteredVacancies;
......@@ -164,6 +176,8 @@ export default class VacancyList extends React.Component {
salary={this.props.salary}
/>
));
console.log(vacancies);
console.log("ini cuy")
vacancies = this.sortVacancies(vacancies);
vacancies = this.filterVacanciesBasedOnSalary(vacancies);
vacancies = this.filterVacanciesBasedOnVacancyStatus(vacancies);
......
import React from 'react';
import { Button, Header, Modal } from 'semantic-ui-react';
export default class VerifyAdminModal extends React.Component {
state = { modalOpen: false }
componentWillUpdate() {
this.fixBody();
}
componentDidUpdate() {
this.fixBody();
}
fixBody = () => {
const anotherModal = document.getElementsByClassName('ui page modals').length;
if (anotherModal > 0) document.body.classList.add('scrolling', 'dimmable', 'dimmed');
};
handleOpen = () => this.setState({
modalOpen: true,
});
handleClose = () => this.setState({
modalOpen: false,
});
render() {
return (
<Modal
trigger={
<Button color="blue" icon="right chevron" labelPosition="right" floated="right" content="ubah" onClick={this.handleOpen} />
}
closeIcon="close"
open={this.state.modalOpen}
onClose={this.handleClose}
>
<Modal.Header>Software Engineer</Modal.Header>
<Modal.Content>
<Modal.Description>
<Header>Deskripsi Lowongan</Header>
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat.
</Modal.Description>
</Modal.Content>
<Modal.Actions>
<Button color="green" floated="right" onClick={this.handleClose}>Verifikasi</Button>
</Modal.Actions>
</Modal>
);
}
}
......@@ -27,6 +27,10 @@ def validate_student_gpa(value):
if value < 0 or value > 4:
raise ValidationError(u"GPA harus merupakan angka antara 0-4")
def validate_toefl_score(value):
if value < 0 or value >677:
raise ValidationError(u"skor toefl harus merupakan angka antara 0-677")
def validate_npm(value):
"""
......
# Generated by Django 2.2.8 on 2019-12-05 04:16
# Generated by Django 2.2.8 on 2019-12-06 12:07
import core.lib.validators
import core.models.accounts
......@@ -32,11 +32,12 @@ class Migration(migrations.Migration):
('created', models.DateTimeField(auto_now_add=True)),
('updated', models.DateTimeField(auto_now=True)),
('description', models.TextField()),
('founded', models.DateField(blank=True, null=True)),
('status', models.IntegerField(default=0, validators=[django.core.validators.MaxValueValidator(2), django.core.validators.MinValueValidator(0)])),
('logo', models.FileField(blank=True, null=True, upload_to=core.models.accounts.get_company_logo_file_path, validators=[core.lib.validators.validate_image_file_extension])),
('address', models.CharField(blank=True, max_length=1000, null=True)),
('category', models.CharField(default='Belum ada kategori perusahaan', max_length=140)),
('size', models.CharField(blank=True, default=0, max_length=10, null=True)),
('size', models.IntegerField(default=1, validators=[django.core.validators.MinValueValidator(1)])),
('website', models.CharField(default='Belum ada link website', max_length=100)),
('linkedin_url', models.URLField(blank=True, null=True)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
......@@ -150,7 +151,7 @@ class Migration(migrations.Migration):
('expected_salary', models.CharField(blank=True, max_length=10, null=True, validators=[django.core.validators.RegexValidator('^\\d{0,10}$')])),
('job_seeking_status', models.CharField(blank=True, max_length=30, null=True)),
('student_gpa', models.FloatField(blank=True, db_column='student_gpa', default=1.0, null=True, validators=[core.lib.validators.validate_student_gpa])),
('student_toefl', models.IntegerField(blank=True, db_column='toefl', default=0, null=True)),
('student_toefl', models.IntegerField(blank=True, db_column='toefl', default=0, null=True, validators=[core.lib.validators.validate_toefl_score])),
('student_toefl_file', models.FileField(blank=True, null=True, upload_to=core.models.accounts.get_student_toefl_file_path, validators=[django.core.validators.FileExtensionValidator(['pdf'])])),
('volunteer', models.CharField(blank=True, max_length=100, null=True)),
('awards', models.CharField(blank=True, max_length=100, null=True)),
......@@ -161,6 +162,7 @@ class Migration(migrations.Migration):
('interests', models.CharField(blank=True, max_length=100, null=True)),
('dependants', models.IntegerField(blank=True, db_column='dependants', default=0, null=True)),
('related_course', models.CharField(blank=True, max_length=200, null=True)),
('ielts', models.FloatField(blank=True, db_column='ielts', default=1.0, null=True)),
('applied_vacancies', models.ManyToManyField(blank=True, related_name='applied_vacancies', through='core.Application', to='core.Vacancy')),
('bookmarked_vacancies', models.ManyToManyField(blank=True, related_name='bookmarked_vacancies', to='core.Vacancy')),
('recommendations', models.ManyToManyField(blank=True, related_name='recommendations', to='core.Recommendation')),
......
# Generated by Django 2.2.8 on 2019-12-06 03:44
# Generated by Django 2.2.8 on 2019-12-06 08:57
import django.core.validators
from django.db import migrations, models
......@@ -10,9 +11,9 @@ class Migration(migrations.Migration):
]
operations = [
migrations.AddField(
migrations.AlterField(
model_name='student',
name='ielts',
field=models.FloatField(blank=True, db_column='ielts', default=1.0, null=True),
name='region',
field=models.CharField(blank=True, max_length=30, null=True, validators=[django.core.validators.RegexValidator('^\\w{0,30}$')]),
),
]
# Generated by Django 2.2.8 on 2019-12-06 09:00
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0002_auto_20191206_1557'),
]
operations = [
migrations.AlterField(
model_name='student',
name='region',
field=models.CharField(blank=True, max_length=30, null=True, validators=[django.core.validators.RegexValidator('^[A-Za-z]+$')]),
),
]
......@@ -7,7 +7,7 @@ from django.core.validators import MinValueValidator, MaxValueValidator, RegexVa
from django.db import models
from core.lib.validators import validate_document_file_extension, validate_image_file_extension, validate_npm, \
validate_student_gpa
validate_student_gpa, validate_toefl_score
def get_student_resume_file_path(instance, filename):
......@@ -101,7 +101,7 @@ class Student(models.Model):
hackerrank_url = models.URLField(max_length=200, blank=True, null=True)
website_url = models.URLField(max_length=200, blank=True, null=True)
work_experience = models.CharField(max_length=500, blank=True, null=True)
region = models.CharField(max_length=30, blank=True, null=True)
region = models.CharField(max_length=30, blank=True, null=True, validators=[RegexValidator(r'^[A-Za-z]+$')])
alamat = models.CharField(max_length=50, blank=True, null=True)
skills = models.CharField(max_length=50, blank=True, null=True)