diff --git a/assets/css/custom.css b/assets/css/custom.css
index 2277100c4acb37fd4c1983f0a0982bcd559a1c41..42b8b0e5f276618c553f613333c1113c34992cb0 100755
--- a/assets/css/custom.css
+++ b/assets/css/custom.css
@@ -163,3 +163,21 @@ card .formRegis{
   color: black;
 }
 
+.biodata h5{
+  line-height: 30%;
+}
+
+.button-profile{
+ margin-top:30px;
+}
+
+.ui.segment.profile-form{
+  padding-bottom: 37px;
+  margin-top:4%;
+}
+
+.profilePage{
+  margin-bottom:40px;
+  margin-left:5%;
+  margin-right:5%;
+}
\ No newline at end of file
diff --git a/assets/js/ProfilePage.jsx b/assets/js/ProfilePage.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..eb331946cbd3fc6c03440b5cddaad96858616c61
--- /dev/null
+++ b/assets/js/ProfilePage.jsx
@@ -0,0 +1,138 @@
+import React from 'react';
+import { Segment, Image, Header, Icon, Container, Button, Form } from 'semantic-ui-react';
+import Server from './lib/Server';
+
+export default class ProfilePage extends React.Component {
+
+  static propTypes = {
+    route: React.PropTypes.object.isRequired,
+    params: React.PropTypes.object.isRequired,
+  };
+
+  constructor(props) {
+    super(props);
+    /* istanbul ignore next */
+    this.state = {
+      id: '',
+      npm: '',
+      name: '',
+      major: '',
+      batch: '',
+      email: '',
+      cityOfBirth: '',
+      dateOfBirth: '',
+      resume: '',
+      phone: '',
+      showTranscript: '',
+    };
+    this.getProfile = this.getProfile.bind(this);
+    this.handleChange = this.handleChange.bind(this);
+    this.getProfile();
+  }
+
+  getProfile() {
+    if (this.props.route.own) {
+      // check api format in /api#!/login
+      this.state = {
+        id: this.props.route.data.student.id,
+        npm: this.props.route.data.student.npm,
+        name: this.props.route.data.student.name,
+        major: this.props.route.data.student.major,
+        batch: this.props.route.data.student.batch,
+        email: this.props.route.data.student.user.email,
+        cityOfBirth: this.props.route.data.student.birth_place,
+        dateOfBirth: this.props.route.data.student.birth_date,
+        resume: this.props.route.data.student.resume,
+        phone: this.props.route.data.student.phone_number,
+        showTranscript: this.props.route.data.student.show_transcript,
+      };
+      return Promise.resolve(this.state);
+    } else {
+      return Server.get(`/students/${this.props.params.id}/`).then((data) => {
+        this.setState({
+          id: data.id,
+          name: data.name,
+          npm: data.npm,
+          resume: data.resume,
+          major: data.major,
+          batch: data.batch,
+          email: data.user.email,
+          cityOfBirth: data.birth_place,
+          dateOfBirth: data.birth_date,
+          phone: data.phone_number,
+          showTranscript: data.show_transcript,
+        });
+      }, error => error.then(() => {
+        // this.modalAlert.open('Gagal Mengambil ', r.error);
+        this.state.name = 'Gagal mendapatkan informasi';
+      }));
+    }
+  }
+
+  handleChange = (e) => {
+    this.setState({ [e.target.name]: e.target.value });
+  };
+
+  updateForm(show) {
+    if (show) {
+      return (
+        <Segment className="profile-form">
+          <Header as="h3" textAlign="center">
+            <Icon name="edit" />
+            <Header.Content>
+              Edit Profile Page
+            </Header.Content>
+          </Header>
+          <Form size="small" onSubmit={this.handleSubmit}>
+            <Form.Field>
+              <label htmlFor="photo">Profile Picture</label>
+              <input onChange={this.handleChange} placeholder="Profile Photo.jpg" name="photo" type="File" />
+            </Form.Field>
+            <Form.Field>
+              <label htmlFor="email">Email</label>
+              <input onChange={this.handleChange} placeholder="jojon@email.com" name="email" />
+            </Form.Field>
+            <Form.Field>
+              <label htmlFor="phone">No. Hp</label>
+              <input onChange={this.handleChange} placeholder="08123456789" name="phone" />
+            </Form.Field>
+            <Form.Field>
+              <label htmlFor="resume">Resume</label>
+              <input onChange={this.handleChange} placeholder="Resume" name="resume" type="File" />
+            </Form.Field>
+            <Button type="submit" size="small" primary floated="right">Submit</Button>
+          </Form>
+        </Segment>
+      );
+    }
+
+    return (<div />);
+  }
+
+  render() {
+    return (
+      <div className="profilePage">
+        <Segment className="biodata-section">
+          <Header as="h2" icon textAlign="center">
+            <Image src="http://semantic-ui.com/images/wireframe/square-image.png" size="small" shape="circular" />
+          </Header>
+          <Container textAlign="center" className="profile-biodata">
+            <div className="biodata">
+              <h3> { this.state.name } </h3>
+              <h5> { this.state.major }, { this.state.batch } </h5>
+              <h5> { this.state.email } </h5>
+              <h5> { this.state.phone } </h5>
+              <h5> { this.state.cityOfBirth}, { this.state.dateOfBirth } </h5>
+            </div>
+            <div className="button-profile">
+              <Button primary size="small">Resume</Button>
+              { this.state.showTranscript ? <Button primary size="small">Transkrip</Button> : <div /> }
+            </div>
+          </Container>
+        </Segment >
+        { this.updateForm(this.props.route.own) }
+      </div>
+
+    );
+  }
+}
diff --git a/assets/js/TranscriptPage.jsx b/assets/js/TranscriptPage.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..69da971a04dc9ff29a685018992d8d78965c93d9
--- /dev/null
+++ b/assets/js/TranscriptPage.jsx
@@ -0,0 +1,59 @@
+import React from 'react';
+import CourseList from './components/CourseList';
+
+export default class TranscriptPage extends React.Component {
+      constructor(props) {
+        super(props);
+        /* istanbul ignore next */
+        this.state = {
+          data: {"transcript":[{
+              "url": "http://api.cs.ui.ac.id/siakngcs/riwayat-mahasiswa/99731/",
+              "npm": "1406622616",
+                "kelas": {
+                    "url": "http://api.cs.ui.ac.id/siakngcs/kelas/473569/",
+                    "kd_kls": "473569",
+                    "nm_kls": "MD 1 - B",
+                    "nm_mk_cl": {
+                        "url": "http://api.cs.ui.ac.id/siakngcs/matakuliah/817/",
+                        "kd_mk": "CSF1600100",
+                        "nm_mk": "Matematika Diskret 1",
+                        "kd_org": "06.00.12.01",
+                        "kd_kur": "06.00.12.01-2012",
+                        "jml_sks": 3
+                    },
+            "kd_kur_cl": "06.00.12.01-2012",
+            "kd_mk_cl": "CSF1600100",
+            "periode": {
+                "url": "http://api.cs.ui.ac.id/siakngcs/periode/25/",
+                "term": 1,
+                "tahun": 2014
+            },
+            "pengajar": [
+                {
+                    "url":
+"http://api.cs.ui.ac.id/siakngcs/dosen/196111251992031001/",
+                    "nomor": "196111251992031001",
+                    "nama": "Prof. Drs. T. Basaruddin M.Sc., Ph.D",
+                    "id_skema": 1,
+                    "nm_skema": "Skema Inti",
+                    "maks_sks": 8
+                }
+            ]
+        },
+        "kd_kls": "473569",
+        "kd_kur": "06.00.12.01-2012",
+        "kd_mk": "CSF1600100",
+        "kd_org": "01.00.12.01",
+        "term": 1,
+        "tahun": 2014,
+        "nilai": "A"
+    }],"name":"Si jagoan neon" }};//ambil dari database
+
+      }
+
+      render() {
+        return (
+          <CourseList data={this.state.data.transcript} name={this.state.data.name}/>
+        );
+  }
+}
diff --git a/assets/js/__test__/ProfilePage-test.jsx b/assets/js/__test__/ProfilePage-test.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..6c725f5b61d4f2fdb5b07649ee42465ccc2d5ab7
--- /dev/null
+++ b/assets/js/__test__/ProfilePage-test.jsx
@@ -0,0 +1,94 @@
+/* eslint-disable no-unused-expressions */
+import React from 'react';
+import ReactTestUtils from 'react-addons-test-utils';
+import fetchMock from 'fetch-mock';
+import ProfilePage from '../ProfilePage';
+
+describe('ProfilePage', () => {
+  const studentSession = {
+    url: 'http://localhost:8000/api/users/9/',
+    username: 'muhammad.reza42',
+    email: 'muhammad.reza42@ui.ac.id',
+    is_staff: false,
+    company: null,
+    supervisor: null,
+    student: {
+      id: 3,
+      user: {
+        url: 'http://localhost:8000/api/users/9/',
+        username: 'muhammad.reza42',
+        email: 'muhammad.reza42@ui.ac.id',
+        is_staff: false,
+      },
+      name: 'Muhammad R.',
+      created: '2017-03-28T13:33:46.147241Z',
+      updated: '2017-03-28T13:33:46.148248Z',
+      npm: 1406543593,
+      resume: null,
+      phone_number: null,
+      birth_place: null,
+      birth_date: null,
+      major: null,
+      batch: null,
+      show_resume: false,
+      bookmarked_vacancies: [
+        3,
+        2,
+      ],
+      applied_vacancies: [
+        3,
+        1,
+      ],
+    },
+  };
+
+  const brokenSession = {
+    url: 'http://localhost:8000/api/users/9/',
+    username: 'muhammad.reza42',
+    email: 'muhammad.reza42@ui.ac.id',
+    is_staff: false,
+    company: null,
+    supervisor: null,
+    student: null,
+  };
+
+  const response = {
+    id: 3,
+    name: 'Muhammad R.',
+    user: {
+      url: 'http://localhost:8000/api/users/9/',
+      username: 'muhammad.reza42',
+      email: 'muhammad.reza42@ui.ac.id',
+      is_staff: false,
+    },
+    npm: 1406543593,
+    resume: null,
+    phone_number: null,
+    birth_place: null,
+    birth_date: null,
+    major: null,
+    batch: null,
+    show_transcript: false,
+  };
+
+  it('renders without problem', () => {
+    const profile = ReactTestUtils.renderIntoDocument(
+      <ProfilePage route={{ own: true, data: studentSession }} params={{}} />);
+    expect(profile.state.name).to.equal(studentSession.student.name);
+  });
+
+  it('get profile for company without problem', () => {
+    fetchMock.get('*', response);
+    const profile = ReactTestUtils.renderIntoDocument(
+      <ProfilePage route={{ own: false, data: studentSession }} params={{ id: 3 }} />);
+    profile.getProfile().then(()=> expect(profile.state.name).to.equal(response.name));
+    fetchMock.restore();
+  });
+
+  it('renders without problem when error getting data', () => {
+    fetchMock.get('*', 400);
+    const profile = ReactTestUtils.renderIntoDocument(
+      <ProfilePage route={{ own: false, data: studentSession }} params={{ id: 3 }} />);
+    profile.getProfile().then(()=> expect(profile.state.name).to.equal('Gagal mendapatkan informasi'));
+  });
+});
diff --git a/assets/js/components/Course.jsx b/assets/js/components/Course.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..8713846243fb6e9d167db438a28b7a81191a717b
--- /dev/null
+++ b/assets/js/components/Course.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import { Table } from 'semantic-ui-react';
+
+export default class Course extends React.Component {
+  static propTypes = {
+    courseName: React.PropTypes.string.isRequired,
+    grade: React.PropTypes.string.isRequired,
+  };
+
+
+  render() {
+    return (
+
+      <Table.Row>
+              <Table.Cell>{this.props.courseName}</Table.Cell>
+              <Table.Cell>{this.props.grade}</Table.Cell>
+          </Table.Row>
+    );
+  }
+}
diff --git a/assets/js/components/CourseList.jsx b/assets/js/components/CourseList.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..cc0357a036eb34c558ba011254d91822636fe4a4
--- /dev/null
+++ b/assets/js/components/CourseList.jsx
@@ -0,0 +1,48 @@
+import React from 'react';
+import { Grid, Segment, Table } from 'semantic-ui-react';
+import Course from './Course';
+export default class CourseList extends React.Component {
+
+  static propTypes = {
+    data: React.PropTypes.array.isRequired,
+    name: React.PropTypes.array.isRequired,
+  };
+
+  constructor(props) {
+    super(props);
+    /* istanbul ignore next */
+    this.state = { course: this.props.data };
+  }
+
+
+  generateCourse() {
+    return this.state.course.map((course, index) =>
+      <Course
+        key={index}
+        courseName={course.kelas.nm_kls}
+        grade={course.nilai}
+      />,
+    );
+  }
+
+  render = () => (
+      <Grid.Column centered>
+
+      <Segment>
+          <h2>Nama : {this.props.name}</h2>
+            <Table unstackable>
+              <Table.Header>
+                <Table.Row>
+                  <Table.HeaderCell>Mata Kuliah</Table.HeaderCell>
+                  <Table.HeaderCell>Nilai</Table.HeaderCell>
+                </Table.Row>
+              </Table.Header>
+
+              <Table.Body>
+              { this.generateCourse() }
+              </Table.Body>
+            </Table>
+      </Segment>
+      </Grid.Column>
+  );
+}
diff --git a/assets/js/index.jsx b/assets/js/index.jsx
index 9f0d2999130144c7a4fbfc3a5517b4ad8124f49e..0d8360d6e437e2f8047784e5e4c910e176ec1d59 100644
--- a/assets/js/index.jsx
+++ b/assets/js/index.jsx
@@ -79,8 +79,6 @@ export default class App extends React.Component {
   };
 
   render() {
-    // const student = this.authorization(['admin', 'student']);
-    // const supervisor = this.authorization(['admin', 'supervisor']);
     const company = this.authorization(['admin', 'company']);
     const commonUser = this.authorization(['admin', 'student', 'company']);
 
diff --git a/core/lib/permissions.py b/core/lib/permissions.py
index d17b4bb2cd8302b0b7441b69967ac591d9634676..2b3b549a80ab61a262d827e9aad979a6f93f2308 100644
--- a/core/lib/permissions.py
+++ b/core/lib/permissions.py
@@ -18,6 +18,10 @@ def is_admin_or_supervisor(user):
     return user.is_superuser or hasattr(user, "supervisor")
 
 
+def is_admin_or_supervisor_or_company(user):
+    return user.is_superuser or hasattr(user, "supervisor") or hasattr(user, "company")
+
+
 class IsAdminOrSelfOrReadOnly(permissions.BasePermission):
     def has_object_permission(self, request, view, obj):
         if request.method in permissions.SAFE_METHODS:
@@ -96,6 +100,30 @@ class IsAdminOrCompany(permissions.BasePermission):
         return hasattr(user, "company") and user.company == company
 
 
+class IsAdminOrSupervisorOrCompany(permissions.BasePermission):
+    def has_permission(self, request, view):
+        return is_admin_or_supervisor_or_company(request.user)
+
+
+class IsAdminOrSupervisorOrCompanyOrSelf(permissions.IsAuthenticated):
+    def has_object_permission(self, request, view, obj):
+        user = request.user
+        if user.is_superuser or hasattr(user, "company") or hasattr(user, "supervisor"):
+            return True
+        if hasattr(user, "student"):
+            if isinstance(obj, Student):
+                student = obj
+            elif hasattr(obj, "student"):
+                student = obj.student
+            else:
+                raise APIException(
+                    "Checking student permission on object {} not associated with Student"
+                        .format(type(obj.__name__))
+                )
+            return hasattr(user, "student") and user.student == student
+        return False
+
+
 class IsAdminOrVacancyOwner(permissions.BasePermission):
     def has_permission(self, request, view):
         return is_admin_or_company(request.user)
diff --git a/core/migrations/0007_auto_20170424_0720.py b/core/migrations/0007_auto_20170424_0720.py
new file mode 100644
index 0000000000000000000000000000000000000000..23313a738e6ba8ff5cae98f8c9863bd17693eb6a
--- /dev/null
+++ b/core/migrations/0007_auto_20170424_0720.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.5 on 2017-04-24 07:20
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0006_auto_20170328_1950'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='student',
+            name='batch',
+            field=models.CharField(blank=True, max_length=4, null=True),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='birth_date',
+            field=models.DateField(blank=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='birth_place',
+            field=models.TextField(blank=True, max_length=100, null=True),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='major',
+            field=models.CharField(blank=True, max_length=100, null=True),
+        ),
+        migrations.AddField(
+            model_name='student',
+            name='show_resume',
+            field=models.BooleanField(default=False),
+        ),
+    ]
diff --git a/core/migrations/0008_auto_20170424_0725.py b/core/migrations/0008_auto_20170424_0725.py
new file mode 100644
index 0000000000000000000000000000000000000000..bacc0ebe121ce7f5e5151b5c9b807c42d3de2d34
--- /dev/null
+++ b/core/migrations/0008_auto_20170424_0725.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.5 on 2017-04-24 07:25
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0007_auto_20170424_0720'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='student',
+            name='birth_place',
+            field=models.CharField(blank=True, max_length=30, null=True),
+        ),
+        migrations.AlterField(
+            model_name='student',
+            name='major',
+            field=models.CharField(blank=True, max_length=30, null=True),
+        ),
+    ]
diff --git a/core/migrations/0009_auto_20170424_0909.py b/core/migrations/0009_auto_20170424_0909.py
new file mode 100644
index 0000000000000000000000000000000000000000..151a05cfde176c36d4db2d6f3f9f9b551d61384e
--- /dev/null
+++ b/core/migrations/0009_auto_20170424_0909.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.5 on 2017-04-24 09:09
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0008_auto_20170424_0725'),
+    ]
+
+    operations = [
+        migrations.RenameField(
+            model_name='student',
+            old_name='show_resume',
+            new_name='show_transcript',
+        ),
+    ]
diff --git a/core/migrations/0010_student_photo.py b/core/migrations/0010_student_photo.py
new file mode 100644
index 0000000000000000000000000000000000000000..2ed279ad7e922b03b5af6ee802dde16189e4a56f
--- /dev/null
+++ b/core/migrations/0010_student_photo.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.5 on 2017-04-24 13:34
+from __future__ import unicode_literals
+
+import core.models.accounts
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0009_auto_20170424_0909'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='student',
+            name='photo',
+            field=models.FileField(blank=True, null=True, upload_to=core.models.accounts.get_student_photo_file_path),
+        ),
+    ]
diff --git a/core/migrations/0011_merge_20170425_2214.py b/core/migrations/0011_merge_20170425_2214.py
new file mode 100644
index 0000000000000000000000000000000000000000..c255ca51038829cd59f9ae8d8131e5a74ed516be
--- /dev/null
+++ b/core/migrations/0011_merge_20170425_2214.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.5 on 2017-04-25 22:14
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0010_student_photo'),
+        ('core', '0007_auto_20170425_1550'),
+    ]
+
+    operations = [
+    ]
diff --git a/core/models/accounts.py b/core/models/accounts.py
index 296851594da3f3abaad2c1f59f9201e9e9de2c47..7fd1d71681bf91579b31a4fa45545d884b4ed0ad 100644
--- a/core/models/accounts.py
+++ b/core/models/accounts.py
@@ -12,6 +12,12 @@ def get_student_resume_file_path(instance, filename):
     return os.path.join("student-resume/", filename)
 
 
+def get_student_photo_file_path(instance, filename):
+    extension = filename.split('.')[-1].lower()
+    filename = "%s.%s" % (uuid.uuid4(), extension)
+    return os.path.join("student-photo/", filename)
+
+
 def get_company_logo_file_path(instance, filename):
     extension = filename.split('.')[-1].lower()
     filename = "%s.%s" % (uuid.uuid4(), extension)
@@ -51,11 +57,21 @@ class Student(models.Model):
     bookmarked_vacancies = models.ManyToManyField('core.Vacancy', related_name="bookmarked_vacancies", blank=True)
     applied_vacancies = models.ManyToManyField('core.Vacancy', related_name="applied_vacancies",
                                                blank=True, through='core.Application')
+    birth_place = models.CharField(max_length=30, blank=True, null=True)
+    birth_date = models.DateField(blank=True, null=True)
+    major = models.CharField(max_length=30, blank=True, null=True)
+    batch = models.CharField(max_length=4, blank=True, null=True)
+    show_transcript = models.BooleanField(default=False)
+    photo = models.FileField(upload_to=get_student_photo_file_path, null=True, blank=True)
 
     @property
     def name(self):
         return get_display_name(self.user)
 
+    @property
+    def full_name(self):
+        return get_display_name(self.user, full_name=True)
+
     def __unicode__(self):
         return u"Student {}".format(get_display_name(self.user))
 
diff --git a/core/serializers/accounts.py b/core/serializers/accounts.py
index 63f67d1aeb70c79943b47001cbcfc4e7393f19b1..25440942f2b519fd502ebb6dac6b6eb1d3b84b6e 100644
--- a/core/serializers/accounts.py
+++ b/core/serializers/accounts.py
@@ -16,7 +16,41 @@ class StudentSerializer(serializers.ModelSerializer):
 
     class Meta:
         model = Student
-        fields = '__all__'
+        fields = ['id', 'name', 'user', 'npm', 'resume', 'phone_number', 'birth_place', 'birth_date', 'major', 'batch', \
+                  'show_transcript', 'photo']
+
+
+class StudentUpdateSerializer(serializers.ModelSerializer):
+    email = serializers.EmailField()
+
+    def to_representation(self, instance):
+        resume = None
+        photo = None
+        if instance.resume and hasattr(instance.resume, 'url'):
+            resume = instance.resume.url
+        if instance.photo and hasattr(instance.photo, 'url'):
+            photo = instance.photo.url
+        return {
+            'resume' : resume,
+            'email' : instance.user.email,
+            'phone_number' : instance.phone_number,
+            'photo' : photo,
+            'show_transcript' : instance.show_transcript
+        }
+
+    def update(self, instance, validated_data):
+        instance.resume = validated_data.get('resume', instance.resume)
+        instance.show_transcript = validated_data.get('show_transcript', instance.show_transcript)
+        instance.phone_number = validated_data.get('phone_number', instance.phone_number)
+        instance.photo = validated_data.get('photo', instance.photo)
+        instance.user.email = validated_data.get('email', instance.user.email)
+        instance.save()
+        instance.user.save()
+        return instance
+
+    class Meta:
+        model = Student
+        fields = ['resume', 'email', 'phone_number', 'photo', 'show_transcript']
 
 
 class CompanySerializer(serializers.ModelSerializer):
diff --git a/core/tests/test_accounts.py b/core/tests/test_accounts.py
index fe6aa42c32287d7f478ce8a647bcce67f4b7dec5..e4889f544f125743816dbbf53186f6e55b88d359 100644
--- a/core/tests/test_accounts.py
+++ b/core/tests/test_accounts.py
@@ -2,13 +2,12 @@ import requests_mock
 from rest_framework import status
 from rest_framework.test import APIClient, APITestCase
 from django.contrib.auth.models import User
-from core.models.accounts import Company, Supervisor
+from core.models.accounts import Company, Supervisor, Student
 
 class LoginTests(APITestCase):
 
     @requests_mock.Mocker()
     def test_succesful_student_login_relogin(self, m):
-
         m.post('https://api.cs.ui.ac.id/authentication/ldap/v2/', json={
                 "username": "dummy.mahasiswa",
                 "nama": "Dummy Mahasiswa",
@@ -17,6 +16,14 @@ class LoginTests(APITestCase):
                 "kodeidentitas": "1234567890",
                 "nama_role": "mahasiswa"
         }, status_code=200)
+        m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890/', json={
+                "kota_lahir": "kota_kota",
+                "tgl_lahir": "2017-12-31",
+                "program": [{
+                    "nm_org" : "Ilmu Informasi",
+                    "angkatan" : "2017"
+                }]
+        }, status_code=200)
 
         url = '/api/login/'
 
@@ -93,3 +100,49 @@ class RegisterTests(APITestCase):
         url = '/api/register/'
         response = self.client.post(url, {'username': 'lalala'}, format='multipart')
         self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+
+class ProfileUpdateTests(APITestCase):
+
+    @requests_mock.Mocker()
+    def test_student_profile_update(self, m):
+        m.post('https://api.cs.ui.ac.id/authentication/ldap/v2/', json={
+            "username": "dummy.mahasiswa",
+            "nama": "Dummy Mahasiswa",
+            "state": 1,
+            "kode_org": "01.00.12.01:mahasiswa",
+            "kodeidentitas": "1234567890",
+            "nama_role": "mahasiswa"
+        }, status_code=200)
+        m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890/', json={
+            "kota_lahir": "kota_kota",
+            "tgl_lahir": "2017-12-31",
+            "program": [{
+                "nm_org": "Ilmu Informasi",
+                "angkatan": "2017"
+            }]
+        }, status_code=200)
+
+        url = '/api/login/'
+        response = self.client.post(url, {'username': 'dummy.mahasiswa', 'password': 'lalala', 'login-type': 'sso-ui'},
+                                    format='json')
+        student_id = response.data.get('student').get('id')
+
+        url = '/api/profiles/students/' + str(student_id) + "/"
+        response = self.client.patch(url, {'phone_number': '08123123123'}, format='multipart')
+        self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
+        self.assertEqual(response.data.get('phone_number'), '08123123123')
+
+        url = '/api/profiles/students/' + str(student_id) + "/"
+        response = self.client.patch(url, {'email': 'saasdasd'}, format='multipart')
+        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+
+        url = '/api/profiles/students/123123123/'
+        response = self.client.patch(url, {'phone_number': '08123123123'}, format='multipart')
+        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+
+        new_user = User.objects.create_user('dummy.student2', 'dummy.student@student.com', 'lalala123')
+        new_student = Student.objects.create(user=new_user, npm="1212121212")
+
+        url = '/api/profiles/students/' + str(new_student.pk) + "/"
+        response = self.client.patch(url, {'phone_number': '08123123123'}, format='multipart')
+        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
diff --git a/core/tests/test_vacancies.py b/core/tests/test_vacancies.py
index bb9829681f771a97e7d83a4485e0c39bbdcf2f43..a79106e84bca448cb2d50e828b05dd9475e631a6 100644
--- a/core/tests/test_vacancies.py
+++ b/core/tests/test_vacancies.py
@@ -20,6 +20,14 @@ class ApplicationTests(APITestCase):
             "kodeidentitas": "1234567890",
             "nama_role": "mahasiswa"
         }, status_code=200)
+        m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890/', json={
+            "kota_lahir": "kota_kota",
+            "tgl_lahir": "2017-12-31",
+            "program": [{
+                "nm_org": "Ilmu Informasi",
+                "angkatan": "2017"
+            }]
+        }, status_code=200)
 
         url = '/api/login/'
 
@@ -41,6 +49,14 @@ class ApplicationTests(APITestCase):
             "kodeidentitas": "1234567890",
             "nama_role": "mahasiswa"
         }, status_code=200)
+        m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890/', json={
+            "kota_lahir": "kota_kota",
+            "tgl_lahir": "2017-12-31",
+            "program": [{
+                "nm_org": "Ilmu Informasi",
+                "angkatan": "2017"
+            }]
+        }, status_code=200)
 
         url = '/api/login/'
 
@@ -72,6 +88,14 @@ class BookmarkApplicationTests(APITestCase):
             "kodeidentitas": "1234567890",
             "nama_role": "mahasiswa"
         }, status_code=200)
+        m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890/', json={
+            "kota_lahir": "kota_kota",
+            "tgl_lahir": "2017-12-31",
+            "program": [{
+                "nm_org": "Ilmu Informasi",
+                "angkatan": "2017"
+            }]
+        }, status_code=200)
 
         url = '/api/login/'
 
@@ -93,6 +117,14 @@ class BookmarkApplicationTests(APITestCase):
             "kodeidentitas": "1234567890",
             "nama_role": "mahasiswa"
         }, status_code=200)
+        m.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/1234567890/', json={
+            "kota_lahir": "kota_kota",
+            "tgl_lahir": "2017-12-31",
+            "program": [{
+                "nm_org": "Ilmu Informasi",
+                "angkatan": "2017"
+            }]
+        }, status_code=200)
 
         url = '/api/login/'
 
diff --git a/core/views/accounts.py b/core/views/accounts.py
index 3f75bb29ca402290a11f7f15d7c641b195d15c56..225d205b46ce063419a83516533a69843f33a683 100644
--- a/core/views/accounts.py
+++ b/core/views/accounts.py
@@ -2,18 +2,18 @@ import requests
 from django.contrib.auth import authenticate, login
 from django.contrib.auth.models import User
 from rest_framework import viewsets, status
+from rest_framework.generics import get_object_or_404
 from rest_framework.decorators import list_route
 from rest_framework.parsers import FormParser,MultiPartParser
 from rest_framework.permissions import AllowAny
 from rest_framework.permissions import IsAdminUser, IsAuthenticated
 from rest_framework.response import Response
-from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_409_CONFLICT
 
-from core.lib.permissions import IsAdminOrStudent, IsAdminOrSelfOrReadOnly, IsAdminOrCompany, IsAdminOrSupervisor
+from core.lib.permissions import IsAdminOrStudent, IsAdminOrSelfOrReadOnly, IsAdminOrCompany, IsAdminOrSupervisor, \
+    IsAdminOrSupervisorOrCompanyOrSelf
 from core.models.accounts import Student, Company, Supervisor
-from core.serializers.accounts import BasicUserSerializer, StudentSerializer, CompanySerializer, SupervisorSerializer, \
-    UserSerializer, RegisterSerializer
-
+from core.serializers.accounts import BasicUserSerializer, UserSerializer, StudentSerializer, CompanySerializer, \
+    SupervisorSerializer, RegisterSerializer, StudentUpdateSerializer
 
 class UserViewSet(viewsets.ModelViewSet):
     queryset = User.objects.all()
@@ -45,6 +45,10 @@ class StudentViewSet(viewsets.ModelViewSet):
     def get_permissions(self):
         if self.action == "update":
             return [IsAdminOrSelfOrReadOnly(), IsAdminOrStudent()]
+        if self.action == "list":
+            return [IsAuthenticated(), IsAdminOrSupervisor()]
+        if self.action == "retrieve":
+            return [IsAuthenticated(), IsAdminOrSupervisorOrCompanyOrSelf()]
         return super(StudentViewSet, self).get_permissions()
 
 
@@ -93,20 +97,26 @@ class LoginViewSet(viewsets.GenericViewSet):
                 last_name = " ".join(name)
                 user, created = User.objects.get_or_create(
                     username=username,
-                    email=username + "@ui.ac.id",
-                    first_name=first_name,
-                    last_name=last_name
+                    defaults={
+                        'email' : username + "@ui.ac.id",
+                        'first_name' : first_name,
+                        'last_name' : last_name
+                    }
                 )
                 user.set_password(password)
                 user.save()
                 login(request, user)
                 if created:
                     if resp.get('nama_role') == "mahasiswa":
+                        student_detail = requests.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/{}/'.format(resp.get("kodeidentitas")))
+                        resp_student_detail = student_detail.json()
                         student = Student.objects.create(
                             user=user,
                             npm=resp.get("kodeidentitas"),
-                            resume=None,
-                            phone_number=None
+                            birth_place=resp_student_detail.get('kota_lahir'),
+                            birth_date=resp_student_detail.get('tgl_lahir'),
+                            major=resp_student_detail.get('program')[0].get('nm_org'),
+                            batch=resp_student_detail.get('program')[0].get('angkatan')
                         )
                         student.save()
                     else:
@@ -177,7 +187,7 @@ class CompanyRegisterViewSet(viewsets.GenericViewSet):
         for attr in ['password', 'email', 'name', 'description', 'logo', 'address']:
             data[attr] = request.data.get(attr)
             if data[attr] is None:
-                return Response({'error': attr+' is required'}, status=HTTP_400_BAD_REQUEST)
+                return Response({'error': attr+' is required'}, status=status.HTTP_400_BAD_REQUEST)
 
         user, created = User.objects.get_or_create(
             username=data['email'],
@@ -199,4 +209,20 @@ class CompanyRegisterViewSet(viewsets.GenericViewSet):
             login(request, user)
             return Response(serializer.data, status=status.HTTP_201_CREATED)
         else:
-            return Response({'error': 'Company with email '+data['email']+' already exist'}, status=HTTP_409_CONFLICT)
+            return Response({'error': 'Company with email '+data['email']+' already exist'}, status=status.HTTP_409_CONFLICT)
+
+
+class StudentProfileViewSet(viewsets.GenericViewSet):
+    queryset = Student.objects.all()
+    permission_classes = [IsAdminOrStudent]
+    serializer_class = StudentUpdateSerializer
+    parser_classes = (MultiPartParser, FormParser,)
+
+    def partial_update(self, request, pk=None):
+        user = self.get_object()
+        serializer = self.serializer_class(user, data=request.data, partial=True)
+        if serializer.is_valid():
+            serializer.save()
+            return Response(serializer.data, status=status.HTTP_202_ACCEPTED)
+        else:
+            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
diff --git a/core/views/vacancies.py b/core/views/vacancies.py
index 242e8f086ad4570806d12a952f391b8f34dc54ba..e26ec3d9df6ef3dbb5c16862648b5b0398de2d1d 100644
--- a/core/views/vacancies.py
+++ b/core/views/vacancies.py
@@ -1,3 +1,5 @@
+import requests
+from django.conf import settings
 from rest_framework import viewsets, status
 from rest_framework.exceptions import ValidationError
 from rest_framework.generics import get_object_or_404
@@ -113,6 +115,20 @@ class CompanyApplicationStatusViewSet(viewsets.GenericViewSet):
         else:
             return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
 
+    def retrieve(self, request, pk=None):
+        application = self.get_object()
+        student = application.student
+        if student.show_transcript:
+            s = requests.Session()
+            credentials = settings.API_CS_CREDENTIALS
+            s.get('https://api.cs.ui.ac.id/api-auth/login/')
+            csrf = s.cookies['csrftoken']
+            resp = s.post('https://api.cs.ui.ac.id/api-auth/login/', data={'username' : credentials["user"], 'password' : credentials["password"], 'csrfmiddlewaretoken' : csrf})
+            response = s.get('https://api.cs.ui.ac.id/siakngcs/mahasiswa/' + str(student.npm) + '/riwayat/')
+            return Response({'name' : student.full_name, 'transcript' : response.json()}, status=status.HTTP_200_OK)
+        else:
+            return Response({'name' : student.full_name, 'error' : 'student does not allow transcript to be shown'}, status=status.HTTP_200_OK)
+
 
 class CompanyVacanciesViewSet(viewsets.GenericViewSet):
     queryset = Vacancy.objects.all()
diff --git a/kape/settings.py b/kape/settings.py
index f3a865d1af8bee89cb2f1a0bfc148e6b5479694f..6a98953da08a9cfa9b39c2cea78d3d3442bb6f63 100755
--- a/kape/settings.py
+++ b/kape/settings.py
@@ -158,3 +158,5 @@ GZIP_CONTENT_TYPES = (
 SESSION_COOKIE_HTTPONLY = False
 
 RUNNING_DEVSERVER = (len(sys.argv) > 1 and sys.argv[1] == 'runserver')
+
+API_CS_CREDENTIALS = {'user' : 'lalala', 'password' : 'lalala'}
diff --git a/kape/urls.py b/kape/urls.py
index db03077136857c0f9165ffd1663e445b6ee3ca5d..da59e3aa14b08d2ed1e43f55f6f1a985d66cd6e4 100755
--- a/kape/urls.py
+++ b/kape/urls.py
@@ -22,7 +22,8 @@ from rest_framework import routers
 from rest_framework_swagger.views import get_swagger_view
 
 from core import apps
-from core.views.accounts import StudentViewSet, CompanyViewSet, SupervisorViewSet, UserViewSet, LoginViewSet, CompanyRegisterViewSet
+from core.views.accounts import StudentViewSet, CompanyViewSet, SupervisorViewSet, UserViewSet, LoginViewSet, \
+    CompanyRegisterViewSet, StudentProfileViewSet
 from core.views.vacancies import VacancyViewSet, BookmarkedVacancyByStudentViewSet, ApplicationViewSet, \
     CompanyApplicationViewSet, CompanyVacanciesViewSet, CompanyApplicationStatusViewSet
 
@@ -35,6 +36,7 @@ router.register(r'supervisors', SupervisorViewSet)
 router.register(r'login', LoginViewSet)
 router.register(r'register', CompanyRegisterViewSet)
 router.register(r'vacancies', VacancyViewSet)
+router.register(r'profiles/students', StudentProfileViewSet)
 router.register(r'applications', CompanyApplicationStatusViewSet)
 router.register(r'students/(?P<student_id>\d+)/bookmarked-vacancies', BookmarkedVacancyByStudentViewSet,
                 base_name='bookmarked-vacancy-list')