diff options
Diffstat (limited to 'app/Template/user_view')
-rw-r--r-- | app/Template/user_view/authentication.php | 27 | ||||
-rw-r--r-- | app/Template/user_view/edit.php | 35 | ||||
-rw-r--r-- | app/Template/user_view/external.php | 11 | ||||
-rw-r--r-- | app/Template/user_view/integrations.php | 13 | ||||
-rw-r--r-- | app/Template/user_view/last.php | 24 | ||||
-rw-r--r-- | app/Template/user_view/layout.php | 19 | ||||
-rw-r--r-- | app/Template/user_view/notifications.php | 26 | ||||
-rw-r--r-- | app/Template/user_view/password.php | 26 | ||||
-rw-r--r-- | app/Template/user_view/password_reset.php | 26 | ||||
-rw-r--r-- | app/Template/user_view/profile.php | 9 | ||||
-rw-r--r-- | app/Template/user_view/sessions.php | 26 | ||||
-rw-r--r-- | app/Template/user_view/share.php | 15 | ||||
-rw-r--r-- | app/Template/user_view/show.php | 40 | ||||
-rw-r--r-- | app/Template/user_view/sidebar.php | 83 | ||||
-rw-r--r-- | app/Template/user_view/timesheet.php | 29 |
15 files changed, 409 insertions, 0 deletions
diff --git a/app/Template/user_view/authentication.php b/app/Template/user_view/authentication.php new file mode 100644 index 00000000..44643388 --- /dev/null +++ b/app/Template/user_view/authentication.php @@ -0,0 +1,27 @@ +<div class="page-header"> + <h2><?= t('Edit Authentication') ?></h2> +</div> +<form method="post" action="<?= $this->url->href('UserViewController', 'authentication', array('user_id' => $user['id'])) ?>" autocomplete="off"> + <?= $this->form->csrf() ?> + + <?= $this->form->hidden('id', $values) ?> + <?= $this->form->hidden('username', $values) ?> + + <?= $this->hook->render('template:user:authentication:form', array('values' => $values, 'errors' => $errors, 'user' => $user)) ?> + + <?= $this->form->checkbox('is_ldap_user', t('Remote user'), 1, isset($values['is_ldap_user']) && $values['is_ldap_user'] == 1) ?> + <?= $this->form->checkbox('disable_login_form', t('Disallow login form'), 1, isset($values['disable_login_form']) && $values['disable_login_form'] == 1) ?> + + <div class="form-actions"> + <button type="submit" class="btn btn-blue"><?= t('Save') ?></button> + <?= t('or') ?> + <?= $this->url->link(t('cancel'), 'UserViewController', 'show', array('user_id' => $user['id'])) ?> + </div> + + <div class="alert alert-info"> + <ul> + <li><?= t('Remote users do not store their password in Kanboard database, examples: LDAP, Google and Github accounts.') ?></li> + <li><?= t('If you check the box "Disallow login form", credentials entered in the login form will be ignored.') ?></li> + </ul> + </div> +</form> diff --git a/app/Template/user_view/edit.php b/app/Template/user_view/edit.php new file mode 100644 index 00000000..18947905 --- /dev/null +++ b/app/Template/user_view/edit.php @@ -0,0 +1,35 @@ +<div class="page-header"> + <h2><?= t('Edit user') ?></h2> +</div> +<form method="post" action="<?= $this->url->href('UserViewController', 'edit', array('user_id' => $user['id'])) ?>" autocomplete="off"> + + <?= $this->form->csrf() ?> + + <?= $this->form->hidden('id', $values) ?> + + <?= $this->form->label(t('Username'), 'username') ?> + <?= $this->form->text('username', $values, $errors, array('required', isset($values['is_ldap_user']) && $values['is_ldap_user'] == 1 ? 'readonly' : '', 'maxlength="50"')) ?> + + <?= $this->form->label(t('Name'), 'name') ?> + <?= $this->form->text('name', $values, $errors) ?> + + <?= $this->form->label(t('Email'), 'email') ?> + <?= $this->form->email('email', $values, $errors) ?> + + <?= $this->form->label(t('Timezone'), 'timezone') ?> + <?= $this->form->select('timezone', $timezones, $values, $errors) ?> + + <?= $this->form->label(t('Language'), 'language') ?> + <?= $this->form->select('language', $languages, $values, $errors) ?> + + <?php if ($this->user->isAdmin()): ?> + <?= $this->form->label(t('Role'), 'role') ?> + <?= $this->form->select('role', $roles, $values, $errors) ?> + <?php endif ?> + + <div class="form-actions"> + <button type="submit" class="btn btn-blue"><?= t('Save') ?></button> + <?= t('or') ?> + <?= $this->url->link(t('cancel'), 'UserViewController', 'show', array('user_id' => $user['id'])) ?> + </div> +</form> diff --git a/app/Template/user_view/external.php b/app/Template/user_view/external.php new file mode 100644 index 00000000..22c25af2 --- /dev/null +++ b/app/Template/user_view/external.php @@ -0,0 +1,11 @@ +<div class="page-header"> + <h2><?= t('External authentications') ?></h2> +</div> + +<?php $html = $this->hook->render('template:user:external', array('user' => $user)) ?> + +<?php if (empty($html)): ?> + <p class="alert"><?= t('No external authentication enabled.') ?></p> +<?php else: ?> + <?= $html ?> +<?php endif ?> diff --git a/app/Template/user_view/integrations.php b/app/Template/user_view/integrations.php new file mode 100644 index 00000000..4a237346 --- /dev/null +++ b/app/Template/user_view/integrations.php @@ -0,0 +1,13 @@ +<div class="page-header"> + <h2><?= t('Integrations') ?></h2> +</div> + +<form method="post" action="<?= $this->url->href('UserViewController', 'integrations', array('user_id' => $user['id'])) ?>" autocomplete="off"> + <?= $this->form->csrf() ?> + <?php $hooks = $this->hook->render('template:user:integrations', array('values' => $values)) ?> + <?php if (! empty($hooks)): ?> + <?= $hooks ?> + <?php else: ?> + <p class="alert"><?= t('No external integration registered.') ?></p> + <?php endif ?> +</form> diff --git a/app/Template/user_view/last.php b/app/Template/user_view/last.php new file mode 100644 index 00000000..3de4d5e2 --- /dev/null +++ b/app/Template/user_view/last.php @@ -0,0 +1,24 @@ +<div class="page-header"> + <h2><?= t('Last logins') ?></h2> +</div> + +<?php if (empty($last_logins)): ?> + <p class="alert"><?= t('Never connected.') ?></p> +<?php else: ?> + <table class="table-small table-fixed"> + <tr> + <th class="column-20"><?= t('Login date') ?></th> + <th class="column-15"><?= t('Authentication method') ?></th> + <th class="column-15"><?= t('IP address') ?></th> + <th><?= t('User agent') ?></th> + </tr> + <?php foreach ($last_logins as $login): ?> + <tr> + <td><?= $this->dt->datetime($login['date_creation']) ?></td> + <td><?= $this->text->e($login['auth_type']) ?></td> + <td><?= $this->text->e($login['ip']) ?></td> + <td><?= $this->text->e($login['user_agent']) ?></td> + </tr> + <?php endforeach ?> + </table> +<?php endif ?>
\ No newline at end of file diff --git a/app/Template/user_view/layout.php b/app/Template/user_view/layout.php new file mode 100644 index 00000000..c3604b99 --- /dev/null +++ b/app/Template/user_view/layout.php @@ -0,0 +1,19 @@ +<section id="main"> + <div class="page-header"> + <?php if ($this->user->hasAccess('UserCreationController', 'show')): ?> + <ul> + <li><i class="fa fa-user fa-fw"></i><?= $this->url->link(t('All users'), 'UserListController', 'show') ?></li> + <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New local user'), 'UserCreationController', 'show', array(), false, 'popover') ?></li> + <li><i class="fa fa-plus fa-fw"></i><?= $this->url->link(t('New remote user'), 'UserCreationController', 'show', array('remote' => 1), false, 'popover') ?></li> + <li><i class="fa fa-upload fa-fw"></i><?= $this->url->link(t('Import'), 'UserImportController', 'show', array(), false, 'popover') ?></li> + <li><i class="fa fa-users fa-fw"></i><?= $this->url->link(t('View all groups'), 'GroupListController', 'index') ?></li> + </ul> + <?php endif ?> + </div> + <section class="sidebar-container" id="user-section"> + <?= $this->render('user_view/sidebar', array('user' => $user)) ?> + <div class="sidebar-content"> + <?= $content_for_sublayout ?> + </div> + </section> +</section> diff --git a/app/Template/user_view/notifications.php b/app/Template/user_view/notifications.php new file mode 100644 index 00000000..84ca1282 --- /dev/null +++ b/app/Template/user_view/notifications.php @@ -0,0 +1,26 @@ +<div class="page-header"> + <h2><?= t('Notifications') ?></h2> +</div> + +<form method="post" action="<?= $this->url->href('UserViewController', 'notifications', array('user_id' => $user['id'])) ?>" autocomplete="off"> + <?= $this->form->csrf() ?> + + <h4><?= t('Notification methods:') ?></h4> + <?= $this->form->checkboxes('notification_types', $types, $notifications) ?> + + <hr> + <h4><?= t('I want to receive notifications for:') ?></h4> + <?= $this->form->radios('notifications_filter', $filters, $notifications) ?> + + <hr> + <?php if (! empty($projects)): ?> + <h4><?= t('I want to receive notifications only for those projects:') ?></h4> + <?= $this->form->checkboxes('notification_projects', $projects, $notifications) ?> + <?php endif ?> + + <div class="form-actions"> + <button type="submit" class="btn btn-blue"><?= t('Save') ?></button> + <?= t('or') ?> + <?= $this->url->link(t('cancel'), 'UserViewController', 'show', array('user_id' => $user['id'])) ?> + </div> +</form> diff --git a/app/Template/user_view/password.php b/app/Template/user_view/password.php new file mode 100644 index 00000000..32ff9d5c --- /dev/null +++ b/app/Template/user_view/password.php @@ -0,0 +1,26 @@ +<div class="page-header"> + <h2><?= t('Password modification') ?></h2> +</div> + +<form method="post" action="<?= $this->url->href('UserViewController', 'password', array('user_id' => $user['id'])) ?>" autocomplete="off"> + + <?= $this->form->hidden('id', $values) ?> + <?= $this->form->csrf() ?> + + <div class="alert alert-error"> + <?= $this->form->label(t('Current password for the user "%s"', $this->user->getFullname()), 'current_password') ?> + <?= $this->form->password('current_password', $values, $errors) ?> + </div> + + <?= $this->form->label(t('New password for the user "%s"', $this->user->getFullname($user)), 'password') ?> + <?= $this->form->password('password', $values, $errors) ?> + + <?= $this->form->label(t('Confirmation'), 'confirmation') ?> + <?= $this->form->password('confirmation', $values, $errors) ?> + + <div class="form-actions"> + <button type="submit" class="btn btn-blue"><?= t('Save') ?></button> + <?= t('or') ?> + <?= $this->url->link(t('cancel'), 'UserViewController', 'show', array('user_id' => $user['id'])) ?> + </div> +</form> diff --git a/app/Template/user_view/password_reset.php b/app/Template/user_view/password_reset.php new file mode 100644 index 00000000..1371ce11 --- /dev/null +++ b/app/Template/user_view/password_reset.php @@ -0,0 +1,26 @@ +<div class="page-header"> + <h2><?= t('Last Password Reset') ?></h2> +</div> + +<?php if (empty($tokens)): ?> + <p class="alert"><?= t('The password has never been reinitialized.') ?></p> +<?php else: ?> + <table class="table-small table-fixed"> + <tr> + <th class="column-20"><?= t('Creation') ?></th> + <th class="column-20"><?= t('Expiration') ?></th> + <th class="column-5"><?= t('Active') ?></th> + <th class="column-15"><?= t('IP address') ?></th> + <th><?= t('User agent') ?></th> + </tr> + <?php foreach ($tokens as $token): ?> + <tr> + <td><?= $this->dt->datetime($token['date_creation']) ?></td> + <td><?= $this->dt->datetime($token['date_expiration']) ?></td> + <td><?= $token['is_active'] == 0 ? t('No') : t('Yes') ?></td> + <td><?= $this->text->e($token['ip']) ?></td> + <td><?= $this->text->e($token['user_agent']) ?></td> + </tr> + <?php endforeach ?> + </table> +<?php endif ?>
\ No newline at end of file diff --git a/app/Template/user_view/profile.php b/app/Template/user_view/profile.php new file mode 100644 index 00000000..9c9d3282 --- /dev/null +++ b/app/Template/user_view/profile.php @@ -0,0 +1,9 @@ +<section id="main"> + <br> + <?= $this->avatar->render($user['id'], $user['username'], $user['name'], $user['email'], $user['avatar_path']) ?> + <ul class="listing"> + <li><?= t('Username:') ?> <strong><?= $this->text->e($user['username']) ?></strong></li> + <li><?= t('Name:') ?> <strong><?= $this->text->e($user['name']) ?: t('None') ?></strong></li> + <li><?= t('Email:') ?> <strong><?= $this->text->e($user['email']) ?: t('None') ?></strong></li> + </ul> +</section>
\ No newline at end of file diff --git a/app/Template/user_view/sessions.php b/app/Template/user_view/sessions.php new file mode 100644 index 00000000..eda3ef7f --- /dev/null +++ b/app/Template/user_view/sessions.php @@ -0,0 +1,26 @@ +<div class="page-header"> + <h2><?= t('Persistent connections') ?></h2> +</div> + +<?php if (empty($sessions)): ?> + <p class="alert"><?= t('No session.') ?></p> +<?php else: ?> + <table class="table-small table-fixed"> + <tr> + <th class="column-20"><?= t('Creation date') ?></th> + <th class="column-20"><?= t('Expiration date') ?></th> + <th class="column-15"><?= t('IP address') ?></th> + <th><?= t('User agent') ?></th> + <th class="column-10"><?= t('Action') ?></th> + </tr> + <?php foreach ($sessions as $session): ?> + <tr> + <td><?= $this->dt->datetime($session['date_creation']) ?></td> + <td><?= $this->dt->datetime($session['expiration']) ?></td> + <td><?= $this->text->e($session['ip']) ?></td> + <td><?= $this->text->e($session['user_agent']) ?></td> + <td><?= $this->url->link(t('Remove'), 'UserViewController', 'removeSession', array('user_id' => $user['id'], 'id' => $session['id']), true) ?></td> + </tr> + <?php endforeach ?> + </table> +<?php endif ?> diff --git a/app/Template/user_view/share.php b/app/Template/user_view/share.php new file mode 100644 index 00000000..9ef150e8 --- /dev/null +++ b/app/Template/user_view/share.php @@ -0,0 +1,15 @@ +<div class="page-header"> + <h2><?= t('Public access') ?></h2> +</div> + +<?php if (! empty($user['token'])): ?> + <div class="listing"> + <ul class="no-bullet"> + <li><strong><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'feed', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li> + <li><strong><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ical', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li> + </ul> + </div> + <?= $this->url->link(t('Disable public access'), 'UserViewController', 'share', array('user_id' => $user['id'], 'switch' => 'disable'), true, 'btn btn-red') ?> +<?php else: ?> + <?= $this->url->link(t('Enable public access'), 'UserViewController', 'share', array('user_id' => $user['id'], 'switch' => 'enable'), true, 'btn btn-blue') ?> +<?php endif ?> diff --git a/app/Template/user_view/show.php b/app/Template/user_view/show.php new file mode 100644 index 00000000..df0affb8 --- /dev/null +++ b/app/Template/user_view/show.php @@ -0,0 +1,40 @@ +<div class="page-header"> + <h2><?= t('Summary') ?></h2> +</div> +<ul class="listing"> + <li><?= t('Username:') ?> <strong><?= $this->text->e($user['username']) ?></strong></li> + <li><?= t('Name:') ?> <strong><?= $this->text->e($user['name']) ?: t('None') ?></strong></li> + <li><?= t('Email:') ?> <strong><?= $this->text->e($user['email']) ?: t('None') ?></strong></li> + <li><?= t('Status:') ?> <strong><?= $user['is_active'] ? t('Active') : t('Inactive') ?></strong></li> +</ul> + +<div class="page-header"> + <h2><?= t('Security') ?></h2> +</div> +<ul class="listing"> + <li><?= t('Role:') ?> <strong><?= $this->user->getRoleName($user['role']) ?></strong></li> + <li><?= t('Account type:') ?> <strong><?= $user['is_ldap_user'] ? t('Remote') : t('Local') ?></strong></li> + <li><?= $user['twofactor_activated'] == 1 ? t('Two factor authentication enabled') : t('Two factor authentication disabled') ?></li> +</ul> + +<div class="page-header"> + <h2><?= t('Preferences') ?></h2> +</div> +<ul class="listing"> + <li><?= t('Timezone:') ?> <strong><?= $this->text->in($user['timezone'], $timezones) ?></strong></li> + <li><?= t('Language:') ?> <strong><?= $this->text->in($user['language'], $languages) ?></strong></li> + <li><?= t('Notifications:') ?> <strong><?= $user['notifications_enabled'] == 1 ? t('Enabled') : t('Disabled') ?></strong></li> +</ul> + +<?php if (! empty($user['token'])): ?> + <div class="page-header"> + <h2><?= t('Public access') ?></h2> + </div> + + <div class="listing"> + <ul class="no-bullet"> + <li><strong><i class="fa fa-rss-square"></i> <?= $this->url->link(t('RSS feed'), 'feed', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li> + <li><strong><i class="fa fa-calendar"></i> <?= $this->url->link(t('iCal feed'), 'ical', 'user', array('token' => $user['token']), false, '', '', true) ?></strong></li> + </ul> + </div> +<?php endif ?> diff --git a/app/Template/user_view/sidebar.php b/app/Template/user_view/sidebar.php new file mode 100644 index 00000000..9a25df16 --- /dev/null +++ b/app/Template/user_view/sidebar.php @@ -0,0 +1,83 @@ +<div class="sidebar"> + <h2><?= t('Information') ?></h2> + <ul> + <?php if ($this->user->hasAccess('UserViewController', 'show')): ?> + <li <?= $this->app->checkMenuSelection('UserViewController', 'show') ?>> + <?= $this->url->link(t('Summary'), 'UserViewController', 'show', array('user_id' => $user['id'])) ?> + </li> + <?php endif ?> + <?php if ($this->user->isAdmin()): ?> + <li> + <?= $this->url->link(t('User dashboard'), 'DashboardController', 'show', array('user_id' => $user['id'])) ?> + </li> + <?php endif ?> + <?php if ($this->user->isAdmin() || $this->user->isCurrentUser($user['id'])): ?> + <li <?= $this->app->checkMenuSelection('UserViewController', 'timesheet') ?>> + <?= $this->url->link(t('Time tracking'), 'UserViewController', 'timesheet', array('user_id' => $user['id'])) ?> + </li> + <li <?= $this->app->checkMenuSelection('UserViewController', 'lastLogin') ?>> + <?= $this->url->link(t('Last logins'), 'UserViewController', 'lastLogin', array('user_id' => $user['id'])) ?> + </li> + <li <?= $this->app->checkMenuSelection('UserViewController', 'sessions') ?>> + <?= $this->url->link(t('Persistent connections'), 'UserViewController', 'sessions', array('user_id' => $user['id'])) ?> + </li> + <li <?= $this->app->checkMenuSelection('UserViewController', 'passwordReset') ?>> + <?= $this->url->link(t('Password reset history'), 'UserViewController', 'passwordReset', array('user_id' => $user['id'])) ?> + </li> + <?php endif ?> + + <?= $this->hook->render('template:user:sidebar:information', array('user' => $user)) ?> + </ul> + + <h2><?= t('Actions') ?></h2> + <ul> + <?php if ($this->user->isAdmin() || $this->user->isCurrentUser($user['id'])): ?> + + <?php if ($this->user->hasAccess('UserViewController', 'edit')): ?> + <li <?= $this->app->checkMenuSelection('UserViewController', 'edit') ?>> + <?= $this->url->link(t('Edit profile'), 'UserViewController', 'edit', array('user_id' => $user['id'])) ?> + </li> + <li <?= $this->app->checkMenuSelection('AvatarFile') ?>> + <?= $this->url->link(t('Avatar'), 'AvatarFile', 'show', array('user_id' => $user['id'])) ?> + </li> + <?php endif ?> + + <?php if ($user['is_ldap_user'] == 0): ?> + <li <?= $this->app->checkMenuSelection('UserViewController', 'password') ?>> + <?= $this->url->link(t('Change password'), 'UserViewController', 'password', array('user_id' => $user['id'])) ?> + </li> + <?php endif ?> + + <?php if ($this->user->isCurrentUser($user['id'])): ?> + <li <?= $this->app->checkMenuSelection('twofactor', 'index') ?>> + <?= $this->url->link(t('Two factor authentication'), 'twofactor', 'index', array('user_id' => $user['id'])) ?> + </li> + <?php elseif ($this->user->hasAccess('twofactor', 'disable') && $user['twofactor_activated'] == 1): ?> + <li <?= $this->app->checkMenuSelection('twofactor', 'disable') ?>> + <?= $this->url->link(t('Two factor authentication'), 'twofactor', 'disable', array('user_id' => $user['id'])) ?> + </li> + <?php endif ?> + + <li <?= $this->app->checkMenuSelection('UserViewController', 'share') ?>> + <?= $this->url->link(t('Public access'), 'UserViewController', 'share', array('user_id' => $user['id'])) ?> + </li> + <li <?= $this->app->checkMenuSelection('UserViewController', 'notifications') ?>> + <?= $this->url->link(t('Notifications'), 'UserViewController', 'notifications', array('user_id' => $user['id'])) ?> + </li> + <li <?= $this->app->checkMenuSelection('UserViewController', 'external') ?>> + <?= $this->url->link(t('External accounts'), 'UserViewController', 'external', array('user_id' => $user['id'])) ?> + </li> + <li <?= $this->app->checkMenuSelection('UserViewController', 'integrations') ?>> + <?= $this->url->link(t('Integrations'), 'UserViewController', 'integrations', array('user_id' => $user['id'])) ?> + </li> + <?php endif ?> + + <?php if ($this->user->hasAccess('UserViewController', 'authentication')): ?> + <li <?= $this->app->checkMenuSelection('UserViewController', 'authentication') ?>> + <?= $this->url->link(t('Edit Authentication'), 'UserViewController', 'authentication', array('user_id' => $user['id'])) ?> + </li> + <?php endif ?> + + <?= $this->hook->render('template:user:sidebar:actions', array('user' => $user)) ?> + </ul> +</div> diff --git a/app/Template/user_view/timesheet.php b/app/Template/user_view/timesheet.php new file mode 100644 index 00000000..92ebafb5 --- /dev/null +++ b/app/Template/user_view/timesheet.php @@ -0,0 +1,29 @@ +<div class="page-header"> + <h2><?= t('Time Tracking') ?></h2> +</div> + +<h3><?= t('Subtask timesheet') ?></h3> +<?php if ($subtask_paginator->isEmpty()): ?> + <p class="alert"><?= t('There is nothing to show.') ?></p> +<?php else: ?> + <table class="table-fixed"> + <tr> + <th class="column-25"><?= $subtask_paginator->order(t('Task'), 'task_title') ?></th> + <th class="column-25"><?= $subtask_paginator->order(t('Subtask'), 'subtask_title') ?></th> + <th class="column-20"><?= $subtask_paginator->order(t('Start'), 'start') ?></th> + <th class="column-20"><?= $subtask_paginator->order(t('End'), 'end') ?></th> + <th class="column-10"><?= $subtask_paginator->order(t('Time spent'), 'time_spent') ?></th> + </tr> + <?php foreach ($subtask_paginator->getCollection() as $record): ?> + <tr> + <td><?= $this->url->link($this->text->e($record['task_title']), 'task', 'show', array('project_id' => $record['project_id'], 'task_id' => $record['task_id'])) ?></td> + <td><?= $this->url->link($this->text->e($record['subtask_title']), 'task', 'show', array('project_id' => $record['project_id'], 'task_id' => $record['task_id'])) ?></td> + <td><?= $this->dt->datetime($record['start']) ?></td> + <td><?= $this->dt->datetime($record['end']) ?></td> + <td><?= n($record['time_spent']).' '.t('hours') ?></td> + </tr> + <?php endforeach ?> + </table> + + <?= $subtask_paginator ?> +<?php endif ?>
\ No newline at end of file |