Fakultas Ilmu Komputer UI

Commit 092ece39 authored by ISNAINI NURUL KHASANAH's avatar ISNAINI NURUL KHASANAH
Browse files

Sprint 3 : mencegah field kosong saat edit profil perusahaan-edit conflict

parents 0bcd7df0 48b39fca
Pipeline #26804 failed with stages
in 4 minutes and 50 seconds
......@@ -7,6 +7,7 @@ import { Doughnut } from 'react-chartjs-2';
import Server from './lib/Server';
import Dumper from './lib/Dumper';
import ModalAlert from './components/ModalAlert';
import DatePicker from "react-datepicker";
export default class CompanyProfile extends React.Component {
static propTypes = {
......@@ -17,19 +18,21 @@ export default class CompanyProfile extends React.Component {
super(props);
this.state = {
id: this.props.user.data.company.id,
name: this.props.user.data.company.name,
address: this.props.user.data.company.address,
category: this.props.user.data.company.category,
description: this.props.user.data.company.description,
website: this.props.user.data.company.website,
logo: this.props.user.data.company.logo,
size: this.props.user.data.company.size,
linkedin_url: this.props.user.data.company.linkedin_url,
name: '',
address: '',
category: '',
description: '',
founded: '',
website: '',
logo: '',
size: '',
linkedin_url: '',
loading: false,
form: {
name: '',
address: '',
description: '',
founded: '',
website: '',
size: '',
},
......@@ -37,6 +40,8 @@ export default class CompanyProfile extends React.Component {
applications: [],
vacancies: [],
};
this.getProfile();
this.getProfile = this.getProfile.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
......@@ -61,6 +66,7 @@ export default class CompanyProfile extends React.Component {
category: result.category,
id: result.id,
description: result.description,
founded: result.founded,
refresh: this.state.refresh + 1,
website: result.website,
size: result.size,
......@@ -150,6 +156,9 @@ export default class CompanyProfile extends React.Component {
-
{this.state.description}
</p>
<p>
Founded: {this.state.founded}
</p>
<p>{this.state.website}</p>
<p>
{this.state.size}
......@@ -228,6 +237,19 @@ karyawan
required
/>
</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
......
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);
});
});
......@@ -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>
);
}
}
......@@ -193,6 +193,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 />
......
......@@ -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>
);
}
}
# Generated by Django 2.2.8 on 2019-12-06 08:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0002_student_ielts'),
]
operations = [
migrations.AddField(
model_name='company',
name='founded',
field=models.DateTimeField(blank=True, null=True),
),
]
# Generated by Django 2.2.8 on 2019-12-06 08:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0003_company_founded'),
]
operations = [
migrations.AlterField(
model_name='company',
name='founded',
field=models.DateField(blank=True, null=True),
),
]
# Generated by Django 2.2.8 on 2019-12-06 09:34
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0004_auto_20191206_1510'),
]
operations = [
migrations.AlterField(
model_name='company',
name='size',
field=models.IntegerField(default=1, validators=[django.core.validators.MinValueValidator(1)]),
),
]
......@@ -161,12 +161,13 @@ class Company(models.Model):
updated = models.DateTimeField(auto_now=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
description = models.TextField()
founded = models.DateField(blank=True, null=True)
status = models.IntegerField(default=NEW, validators=[MaxValueValidator(2), MinValueValidator(0)])
logo = models.FileField(upload_to=get_company_logo_file_path, null=True, blank=True,
validators=[validate_image_file_extension])
address = models.CharField(max_length=1000, blank=True, null=True)
category = models.CharField(max_length=140, default="Belum ada kategori perusahaan")
size = models.CharField(max_length=10, default=0, null=True, blank=True)
size = models.IntegerField(default=1, validators=[MinValueValidator(1)])
website = models.CharField(max_length=100, default="Belum ada link website")
linkedin_url = models.URLField(max_length=200, blank=True, null=True)
......
......@@ -175,6 +175,7 @@ class CompanyUpdateSerializer(serializers.ModelSerializer):
return {
'address': instance.address,
'description': instance.description,
'founded': instance.founded,
'name': instance.user.first_name,
'website': instance.website,
'linkedin_url': instance.linkedin_url,
......@@ -185,8 +186,8 @@ class CompanyUpdateSerializer(serializers.ModelSerializer):
instance.address = validated_data.get('address', instance.address)
instance.website = validated_data.get('website', instance.website)
instance.size = validated_data.get('size', instance.size)
instance.description = validated_data.get(
'description', instance.description)
instance.description = validated_data.get('description', instance.description)
instance.founded = validated_data.get('founded', instance.founded)
instance.user.first_name = validated_data.get(
'name', instance.user.first_name)
instance.linkedin_url = validated_data.get('linkedin_url', instance.linkedin_url)
......@@ -196,7 +197,7 @@ class CompanyUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = ['address', 'description', 'name', 'website', 'linkedin_url', 'size']
fields = ['address', 'description', 'founded', 'name', 'website', 'linkedin_url', 'size']
class CompanySerializer(serializers.ModelSerializer):
......
......@@ -92,6 +92,7 @@ class RegisterTests(APITestCase):
def test_create_and_recreate(self):
url = '/api/register/'
tc_post = {'password': 'corporatepass', 'name': 'tutuplapak', 'description': 'menutup lapak',
'founded': '2019-01-01',
'email': 'email@email.com',
'logo': 'lalala', 'address': 'alamat', 'category': 'Perusahaan Jasa',
'website': 'www.tutuplapak.com', 'size': '1000'}
......@@ -486,9 +487,18 @@ class ProfileUpdateTests(APITestCase):
response = self.client.patch(url, {'description': 'Masak-Masak'}, format='multipart')
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
response = self.client.patch(url, {'founded': '2019-01-01'}, format='multipart')
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
response = self.client.patch(url, {'size': '1000'}, format='multipart')
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
response = self.client.patch(url, {'size': '-1'}, format='multipart')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
response = self.client.patch(url, {'size': 'tulisan'}, format='multipart')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
response = self.client.patch(url, {'website': 'www.huehue.com'}, format='multipart')
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
......@@ -498,6 +508,33 @@ class ProfileUpdateTests(APITestCase):
response = self.client.patch(url, {'linkedin_url': 'this is not valid url'}, format='multipart')
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def test_company_profile_update_at_once(self):
new_user = User.objects.create_user('dummy.login.company', 'dummy.login.company@company.com', 'lalala123')
Company.objects.create(user=new_user, description="lalalala", status=Company.VERIFIED, logo=None, address=None)
url = '/api/login/'
response = self.client.post(url, {'username': 'dummy.login.company', 'password': 'lalala123',
'login-type': 'company'},
format='json')
company_id = response.data.get('company').get('id')
url = '/api/companies/' + str(company_id) + "/profile/"
response = self.client.patch(url, {'name': 'Restopedia', 'address': 'Isekai', 'description': 'Masak-Masak',
'size': '1000', 'website': 'www.huehue.com',
'linkedin_url': 'https://www.linkedin.com/company/bob'
}, format='multipart')
company = Company.objects.get(pk=company_id)
self.assertEqual(company.user.first_name, 'Restopedia')
self.assertEqual(company.address, 'Isekai')
self.assertEqual(company.description, 'Masak-Masak')
self.assertEqual(company.size, 1000)
self.assertEqual(company.website, 'www.huehue.com')
self.assertEqual(company.linkedin_url, 'https://www.linkedin.com/company/bob')
class ResponseApiLoginCompany(APITestCase):
def setUp(self):
self.username = "fesbuk"
......@@ -533,9 +570,9 @@ class TranscriptTest(APITestCase):
format='json')
student_id = response.data.get('student').get('id')
url = '/api/students/' + str(student_id) + "/transcript/"
response = self.client.get(url)
self.assertEqual(response.json()['name'], 'Dummy Mahasiswa')
self.assertEqual(response.json()['error'], 'student does not allow transcript to be shown')
\ No newline at end of file
self.assertEqual(response.json()['error'], 'student does not allow transcript to be shown')
......@@ -13,7 +13,7 @@ from core.models.vacancies import Vacancy, Application, VacancyMilestone
from core.serializers.vacancies import VacancySerializer
from core.tests.mocks import mock_csui_oauth_verify, mock_csui_ldap_student, mock_csui_siak_student
from core.views.vacancies import date_validator
from core.views import views_constants
class ApplicationTests(APITestCase):
def get_student_id(self, mock_obj):
......@@ -55,7 +55,7 @@ class ApplicationTests(APITestCase):
close_time=(timezone.now() + timedelta(days=1)))
url = '/api/students/' + str(student_id) + '/applied-vacancies/'
response = self.client.post(url, {'vacancy_id': new_vacancy.pk, 'cover_letter': 'this is a cover letter.'},
response = self.client.post(url, {'vacancy_id': new_vacancy.pk, 'cover_letter': 'this is a cover letter. ' * 50},
format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
......@@ -63,6 +63,51 @@ class ApplicationTests(APITestCase):
response = self.client.delete(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
@requests_mock.Mocker()
def test_application_cover_letter_validation_error(self, m):
student_id = self.get_student_id(m)
new_user = User.objects.create_user(
'dummy.company',
'dummy.company@company.com',
'lalala123'
)
new_company = Company.objects.create(
user=new_user,
description="lalala",
status=Company.VERIFIED,
logo=None,
address=None
)
new_vacancy = Vacancy.objects.create(
company=new_company,
verified=True,
open_time=datetime.fromtimestamp(1541319300.0),
description="lalala",
max_accepted_applicants=3,
working_period="3 Bulan",
requirements="requirements",
close_time=(timezone.now() + timedelta(days=1))
)
url = '/api/students/' + str(student_id) + '/applied-vacancies/'
response = self.client.post(
url,
{
'vacancy_id': new_vacancy.pk,
'cover_letter': 'this is a cover letter.'
},
format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
message_error = response.data[0]
self.assertEqual(message_error, views_constants.ERROR_WORDS_COUNT)
def test_count_application_a_person_is_already_register(self):
new_user = User.objects.create_user('dummy.company', 'dummy.company@company.com', 'lalala123')
new_user2 = User.objects.create_user('dummy.student', 'dummy.student@student.com', 'lalala123')
......