diff --git a/db/migrations/stored/R__functions.sql b/db/migrations/stored/R__functions.sql
index b7dcb4a476bf28a681b6a8bb03a286ba20399263..4df232da3f08c3493dece62ec64ad2ec9839d7fa 100644
--- a/db/migrations/stored/R__functions.sql
+++ b/db/migrations/stored/R__functions.sql
@@ -2264,4 +2264,22 @@ BEGIN
     RETURN IF(vCreated, vToken, '');
 END//
 
+# -------------------------------------------------------------------------------------------
+# Label: roles
+# -------------------------------------------------------------------------------------------
+
+DROP FUNCTION IF EXISTS SetRole//
+CREATE FUNCTION `SetRole` (
+    `pID` INT,
+    `pRole` INT
+) RETURNS tinyint(1)
+NO SQL
+    BEGIN
+        DECLARE EXIT HANDLER FOR SQLEXCEPTION RETURN 0;
+        UPDATE `accounts`
+        SET accounts.UserRoleID = pRole
+        WHERE accounts.ID = pID;
+        RETURN 1;
+    END //
+
 DELIMITER ;
diff --git a/db/migrations/stored/R__procedures.sql b/db/migrations/stored/R__procedures.sql
index a90821d2eaf4e27585122890e9cf11e3f70e0e5b..d2c0719ad599c87e9266b430085f515987a88f10 100644
--- a/db/migrations/stored/R__procedures.sql
+++ b/db/migrations/stored/R__procedures.sql
@@ -284,6 +284,7 @@ BEGIN
                 accounts.FirstName,
                 accounts.SecondName,
                 user_roles.Type,
+                accounts.UserRoleID AS 'RoleID',
                 user_roles.RoleName AS 'Role',
                 user_roles.Mark     AS 'RoleMark',
                 accounts.IsEnabled,
@@ -314,6 +315,7 @@ BEGIN
                 accounts.FirstName,
                 accounts.SecondName,
                 user_roles.Type,
+                accounts.UserRoleID AS 'RoleID',
                 user_roles.RoleName AS 'Role',
                 user_roles.Mark     AS 'RoleMark',
                 accounts.IsEnabled,
@@ -1454,4 +1456,20 @@ BEGIN
     END IF;
 END//
 
+# -------------------------------------------------------------------------------------------
+# Label: roles
+# -------------------------------------------------------------------------------------------
+
+DROP PROCEDURE IF EXISTS GetRoles//
+CREATE PROCEDURE `GetRoles` ()
+NO SQL
+  BEGIN
+    SELECT
+      user_roles.ID       AS 'ID',
+      user_roles.Mark     AS 'RoleMark',
+      user_roles.RoleName AS 'RoleName'
+    FROM `user_roles`
+    WHERE user_roles.Type='teacher';
+  END //
+
 DELIMITER ;
diff --git a/db/stored/functions.sql b/db/stored/functions.sql
index 81fdaaead43e8d6b7f8686b61325b7efd79b99d9..76f508ce0fa40e9c4956788a30e3da4db48b74ec 100644
--- a/db/stored/functions.sql
+++ b/db/stored/functions.sql
@@ -2075,7 +2075,23 @@ BEGIN
 END //
 
 
+# -------------------------------------------------------------------------------------------
+# Label: roles
+# -------------------------------------------------------------------------------------------
 
+DROP FUNCTION IF EXISTS SetRole//
+CREATE FUNCTION `SetRole` (
+        `pID` INT,
+        `pRole` INT
+    ) RETURNS tinyint(1)
+    NO SQL
+BEGIN
+    DECLARE EXIT HANDLER FOR SQLEXCEPTION RETURN 0;
+    UPDATE `accounts`
+        SET accounts.UserRoleID = pRole
+        WHERE accounts.ID = pID;
+    RETURN 1;
+END //
 
 
 # -------------------------------------------------------------------------------------------
diff --git a/db/stored/procedures.sql b/db/stored/procedures.sql
index 48e5afff564277f77e3209f7c83b328ea6067a25..c6434c7c61083defc513daa2581eed37ac1e221c 100644
--- a/db/stored/procedures.sql
+++ b/db/stored/procedures.sql
@@ -1306,6 +1306,42 @@ BEGIN
 END //
 
 
+# -------------------------------------------------------------------------------------------
+# Label: roles
+# -------------------------------------------------------------------------------------------
+
+/*DROP PROCEDURE IF EXISTS GetAccountInfo//
+CREATE PROCEDURE `GetAccountInfo`
+(IN `pID` INT)
+    NO SQL
+BEGIN
+    SELECT
+            view_teachers.LastName   AS 'LastName',
+            view_teachers.FirstName  AS 'FirstName',
+            view_teachers.SecondName AS 'SecondName',
+            view_teachers.FacultyID  AS 'facultyID',
+            user_roles.ID            AS 'roleID',
+            user_roles.Type          AS 'roleType',
+            user_roles.RoleName      AS 'roleName'
+        FROM `view_teachers`
+        INNER JOIN `accounts`   ON accounts.ID = view_teachers.AccountID
+        INNER JOIN `user_roles` ON user_roles.ID = accounts.UserRoleID
+        WHERE view_teachers.AccountID = pID
+        LIMIT 1;
+END //*/
+
+DROP PROCEDURE IF EXISTS GetRoles//
+CREATE PROCEDURE `GetRoles` ()
+    NO SQL
+BEGIN
+    SELECT
+            user_roles.ID       AS 'ID',
+            user_roles.Mark     AS 'RoleMark',
+            user_roles.RoleName AS 'RoleName'
+        FROM `user_roles`
+        WHERE user_roles.Type='teacher';
+END //
+
 
 # -------------------------------------------------------------------------------------------
 # Label: recovery
diff --git a/~dev_rating/application/classes/Controller/Office/Roles.php b/~dev_rating/application/classes/Controller/Office/Roles.php
new file mode 100644
index 0000000000000000000000000000000000000000..31e70aab9c87d461011e38e3e6a69dc3f2010a89
--- /dev/null
+++ b/~dev_rating/application/classes/Controller/Office/Roles.php
@@ -0,0 +1,50 @@
+<?php defined('SYSPATH') or die('No direct script access.');
+
+class Controller_Office_Roles extends Controller_Environment_Office
+{
+    protected static function checkRole($roleID, $roles)
+    {
+        foreach ($roles as $role) {
+            if ( $role['ID'] == $roleID )
+                return true;
+        }
+        return false;
+    }
+
+    public function action_change() {
+        $ID = $this->request->param('id');
+
+        if( !$this->user->isAdmin() )
+            throw HTTP_Exception::factory(403, "У вас нет прав менять роли.");
+
+        if( (int)$ID == 0 )
+            throw HTTP_Exception::factory(400, "Не задан ID преподавателя.");
+
+        $role = (int) $this->request->post('role');
+        $roles = Model_Roles::getRoles();
+
+        $res = false;
+        if(self::checkRole($role, $roles)) {
+            $setRoleResult = Model_Roles::setRole($ID, $role);
+            if($setRoleResult)
+                $res = "Роль изменена";
+            else
+                $res = "Роль не изменена";
+        } elseif($role > 0) {
+            $res = "Недопустимая роль";
+        }
+
+        $user  = Model_Roles::getAccountInfo($ID, $this->user->SemesterID);
+
+        $display = [
+            'result'        => $res,
+            'tID'           => $ID,
+            'tName'         => $user['name'],
+            'tRole'         => $user['RoleID'],
+            'tRoleName'     => $user['Role'],
+            'tRoleVariants' => $roles
+        ];
+
+        $this->twig->set_filename(static::OFFICE . 'roles/change')->set($display);
+    }
+}
diff --git a/~dev_rating/application/classes/Model/Roles.php b/~dev_rating/application/classes/Model/Roles.php
new file mode 100644
index 0000000000000000000000000000000000000000..d7ee0b5672df7af3027b87143c46a244932a4934
--- /dev/null
+++ b/~dev_rating/application/classes/Model/Roles.php
@@ -0,0 +1,41 @@
+<?php defined('SYSPATH') or die('No direct script access.');
+
+/**
+ * @property $ID int
+ * @property $Name string
+ * @property $Role string
+ */
+class Model_Roles extends Model
+{
+    public static function getAccountInfo($uID, $sID) {
+        $sql = 'CALL `GetFullInfo`(:pUserID, :pSemesterID)';
+        $res = DB::query(Database::SELECT, $sql)
+            ->parameters([
+                ':pUserID' => $uID,
+                ':pSemesterID' => $sID,
+            ])->execute()[0];
+        $res['name'] = $res['LastName'].' '.$res['FirstName'].' '.$res['SecondName'];
+        return $res;
+    }
+    
+    public static function getRoles() {
+        $sql = 'CALL `GetRoles`()';
+        return DB::query(Database::SELECT, $sql)->execute()->as_array();
+    }
+    
+    public static function setRole($ID, $role) {
+        $sql = 'SELECT `SetRole`(:pID, :pRole)';
+        $result = '';
+        if(
+            DB::query(Database::SELECT, $sql)
+                ->parameters([
+                    ':pID'      => $ID,
+                    ':pRole'    => $role,
+                ])->execute()
+        )
+            $result = true;
+        else
+            $result = false;
+        return $result;
+    }
+}
diff --git a/~dev_rating/application/views/controls/searchStudent.twig b/~dev_rating/application/views/controls/searchStudent.twig
index b00bcb724d5f6119e0859095360cb9ca39de1062..698f1b6f4d6ef14dc477498560d305e4eda5deff 100644
--- a/~dev_rating/application/views/controls/searchStudent.twig
+++ b/~dev_rating/application/views/controls/searchStudent.twig
@@ -1,5 +1,6 @@
 {% macro head(HandlerURL) %}
     {{ HTML.script('static/js/libs/mustache.min.js')|raw }}
+    {{ HTML.script('static/js/optionLoader.js')|raw }}
     {{ HTML.script('static/js/controls/search.js')|raw }}
     {{ HTML.style('static/css/controls/search.css')|raw }}
     <script>
diff --git a/~dev_rating/application/views/office/roles/change.twig b/~dev_rating/application/views/office/roles/change.twig
new file mode 100644
index 0000000000000000000000000000000000000000..c5cc814c73306bd9ad4134a296fa96b30410a16f
--- /dev/null
+++ b/~dev_rating/application/views/office/roles/change.twig
@@ -0,0 +1,32 @@
+{% extends "office/base" %}
+
+{% block title %}Изменение роли{% endblock %}
+
+{% block office_content %}
+    <h2>Изменение роли преподавателя</h2>
+
+    {% if result %}
+            <script>
+                $(document).ready(function () {
+                    Popup.success('{{ result }}');
+                });
+            </script>
+    {% endif %}
+    <div id="roleDescription">
+        Роль преподавателя {{ tName }}: {{ tRoleName }}.<br />
+        Выберите новую роль:
+    </div>
+    <div id="roleVariants">
+        <form action="" method="post">
+            {% for row in tRoleVariants %}
+                <div class="roleVariant">
+                    <input type="radio" name="role" id="{{ row.ID }}" value="{{ row.ID }}" {{ row.ID == tRole ? 'checked' }} />
+                    <label for="{{ row.ID }}">{{ row.RoleName }}</label>
+                </div>
+            {% endfor %}
+
+            <input type="submit" value="Применить" />
+        </form>
+    </div>
+
+{% endblock %}
\ No newline at end of file
diff --git a/~dev_rating/application/views/office/students/search.twig b/~dev_rating/application/views/office/students/search.twig
index 7be5bc3517ef3d98791ccb9ebee54658f278204a..d208975e4a87f147a213b2fc05bf6951f4b6b278 100644
--- a/~dev_rating/application/views/office/students/search.twig
+++ b/~dev_rating/application/views/office/students/search.twig
@@ -14,7 +14,7 @@
     <div class="goodClearFix">
         <div class="defaultForm FLeft">
             <div class="FirstLine">
-                <a href="{{ URL.site('office/students/[# ID #]') }}">
+                <a href="{{ URL.site('office/students/profile/[# ID #]') }}">
                     [# LastName #] [# FirstName #] [# SecondName #]
                 </a>
             </div>
diff --git a/~dev_rating/application/views/office/teachers/profile.twig b/~dev_rating/application/views/office/teachers/profile.twig
index b62935e36d95c0368e8e79def42139eca8e1275d..172f3869f85e9cee4a5b040482fd309b159d27a0 100644
--- a/~dev_rating/application/views/office/teachers/profile.twig
+++ b/~dev_rating/application/views/office/teachers/profile.twig
@@ -37,11 +37,11 @@
                 </div>
                 <div class="profile_clearFix">
                     <div class="label">ID:</div>
-                    <div class="labeled_info">{{ Account.ID|default('—') }}</div>
+                    <div class="labeled_info">{{ Account.ID }}</div>
                 </div>
                 <div class="profile_clearFix">
                     <div class="label">Роль:</div>
-                    <div class="labeled_info">{{ Account.Role|default('—') }}</div>
+                    <div class="labeled_info">{{ Account.Role }} <a href="../../roles/change/{{ Account.ID }}">Изменить</a></div>
                 </div>
             </div>
         {% endif %}
diff --git a/~dev_rating/application/views/office/teachers/search.twig b/~dev_rating/application/views/office/teachers/search.twig
index a2162146a26856544a2a98d3b22e9f00130d0522..5733d87f70cd272f71b8fc5ca4d4363352ec2eac 100644
--- a/~dev_rating/application/views/office/teachers/search.twig
+++ b/~dev_rating/application/views/office/teachers/search.twig
@@ -12,7 +12,7 @@
     <div class="goodClearFix">
         <div class="defaultForm FLeft Width65">
             <div class="FirstLine">
-                <a href="{{ URL.site('office/teachers/[# ID #]') }}">
+                <a href="{{ URL.site('office/teachers/profile/[# ID #]') }}">
                     [# LastName #] [# FirstName #] [# SecondName #]
                 </a>
             </div>