optimize detail pages, add new permission for comment posting (#1432)
This commit is contained in:
10
UPGRADING.md
10
UPGRADING.md
@@ -8,6 +8,16 @@ you can upgrade your Kimai installation to the latest stable release.
|
||||
Check below if there are more version specific steps required, which need to be executed after the normal update process.
|
||||
Perform EACH version specific task between your version and the new one, otherwise you risk data inconsistency or a broken installation.
|
||||
|
||||
## [1.8](https://github.com/kevinpapst/kimai2/releases/tag/1.8)
|
||||
|
||||
New permissions:
|
||||
|
||||
- `comments_create_customer` - NEW: permission that allows to add new comments for customers
|
||||
- `comments_create_team_customer` - NEW: permission that allows to add new comments for team members of the current customer
|
||||
- `comments_create_teamlead_customer` - NEW: permission that allows to add new comments for a teamlead of the current customer
|
||||
- `edit_teamlead_project` - removed default permission from ROLE_TEAMLEAD (if you use it: change it in the Role & Permission UI)
|
||||
- `edit_teamlead_customer` - removed default permission from ROLE_TEAMLEAD (if you use it: change it in the Role & Permission UI)
|
||||
|
||||
## [1.7](https://github.com/kevinpapst/kimai2/releases/tag/1.7)
|
||||
|
||||
**New database tables and fields were created, don't forget to [run the updater](https://www.kimai.org/documentation/updates.html).**
|
||||
|
||||
@@ -87,14 +87,14 @@ kimai:
|
||||
sets:
|
||||
ACTIVITIES: ['view_activity','create_activity','edit_activity','budget_activity','delete_activity']
|
||||
ACTIVITIES_TEAMLEAD: ['view_activity','create_activity','edit_teamlead_activity','budget_teamlead_activity']
|
||||
PROJECTS: ['view_project','create_project','edit_project','budget_project','delete_project','permissions_project','comments_project','details_project']
|
||||
PROJECTS_ALL_TEAMLEAD: ['view_teamlead_project','edit_teamlead_project','budget_teamlead_project','permissions_teamlead_project','comments_teamlead_project','details_teamlead_project']
|
||||
PROJECTS_ALL_TEAM: ['view_team_project','edit_team_project','budget_team_project','comments_team_project','details_team_project']
|
||||
PROJECTS_TEAMLEAD: ['view_teamlead_project','edit_teamlead_project','budget_teamlead_project','comments_teamlead_project','details_teamlead_project']
|
||||
CUSTOMERS: ['view_customer','create_customer','edit_customer','budget_customer','delete_customer','permissions_customer','comments_customer','details_customer']
|
||||
CUSTOMERS_ALL_TEAMLEAD: ['view_teamlead_customer','edit_teamlead_customer','budget_teamlead_customer','permissions_teamlead_customer','comments_teamlead_customer','details_teamlead_customer']
|
||||
CUSTOMERS_ALL_TEAM: ['view_team_customer','edit_team_customer','budget_team_customer','comments_team_customer','details_team_customer']
|
||||
CUSTOMERS_TEAMLEAD: ['view_teamlead_customer','edit_teamlead_customer','budget_teamlead_customer','comments_teamlead_customer','details_teamlead_customer']
|
||||
PROJECTS: ['view_project','create_project','edit_project','budget_project','delete_project','permissions_project','comments_project','comments_create_project','details_project']
|
||||
PROJECTS_ALL_TEAMLEAD: ['view_teamlead_project','edit_teamlead_project','budget_teamlead_project','permissions_teamlead_project','comments_teamlead_project','comments_create_teamlead_project','details_teamlead_project']
|
||||
PROJECTS_ALL_TEAM: ['view_team_project','edit_team_project','budget_team_project','comments_team_project','comments_create_team_project','details_team_project']
|
||||
PROJECTS_TEAMLEAD: ['view_teamlead_project','budget_teamlead_project','comments_teamlead_project','comments_create_teamlead_project','details_teamlead_project']
|
||||
CUSTOMERS: ['view_customer','create_customer','edit_customer','budget_customer','delete_customer','permissions_customer','comments_customer','comments_create_customer','details_customer']
|
||||
CUSTOMERS_ALL_TEAMLEAD: ['view_teamlead_customer','edit_teamlead_customer','budget_teamlead_customer','permissions_teamlead_customer','comments_teamlead_customer','comments_create_teamlead_customer','details_teamlead_customer']
|
||||
CUSTOMERS_ALL_TEAM: ['view_team_customer','edit_team_customer','budget_team_customer','comments_team_customer','comments_create_team_customer','details_team_customer']
|
||||
CUSTOMERS_TEAMLEAD: ['view_teamlead_customer','budget_teamlead_customer','comments_teamlead_customer','comments_create_teamlead_customer','details_teamlead_customer']
|
||||
INVOICE: ['view_invoice','create_invoice']
|
||||
INVOICE_TEMPLATE: ['manage_invoice_template']
|
||||
TIMESHEET: ['view_own_timesheet','start_own_timesheet','stop_own_timesheet','create_own_timesheet','edit_own_timesheet','export_own_timesheet','delete_own_timesheet']
|
||||
|
||||
@@ -168,7 +168,7 @@ final class CustomerController extends AbstractController
|
||||
|
||||
/**
|
||||
* @Route(path="/{id}/comment_add", name="customer_comment_add", methods={"POST"})
|
||||
* @Security("is_granted('edit', customer) and is_granted('comments', customer)")
|
||||
* @Security("is_granted('comments_create', customer)")
|
||||
*/
|
||||
public function addCommentAction(Customer $customer, Request $request)
|
||||
{
|
||||
@@ -271,12 +271,8 @@ final class CustomerController extends AbstractController
|
||||
$teams = null;
|
||||
$projects = null;
|
||||
|
||||
if ($this->isGranted('edit', $customer)) {
|
||||
$commentForm = $this->getCommentForm($customer, new CustomerComment())->createView();
|
||||
|
||||
if ($this->isGranted('create_team')) {
|
||||
$defaultTeam = $teamRepository->findOneBy(['name' => $customer->getName()]);
|
||||
}
|
||||
if ($this->isGranted('edit', $customer) && $this->isGranted('create_team')) {
|
||||
$defaultTeam = $teamRepository->findOneBy(['name' => $customer->getName()]);
|
||||
}
|
||||
|
||||
if (null !== $customer->getTimezone()) {
|
||||
@@ -291,6 +287,10 @@ final class CustomerController extends AbstractController
|
||||
$comments = $this->repository->getComments($customer);
|
||||
}
|
||||
|
||||
if ($this->isGranted('comments_create', $customer)) {
|
||||
$commentForm = $this->getCommentForm($customer, new CustomerComment())->createView();
|
||||
}
|
||||
|
||||
if ($this->isGranted('permissions', $customer) || $this->isGranted('details', $customer) || $this->isGranted('view_team')) {
|
||||
$teams = $customer->getTeams();
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ final class ProjectController extends AbstractController
|
||||
|
||||
/**
|
||||
* @Route(path="/{id}/comment_add", name="project_comment_add", methods={"POST"})
|
||||
* @Security("is_granted('edit', project) and is_granted('comments', project)")
|
||||
* @Security("is_granted('comments_create', project)")
|
||||
*/
|
||||
public function addCommentAction(Project $project, Request $request)
|
||||
{
|
||||
@@ -273,12 +273,8 @@ final class ProjectController extends AbstractController
|
||||
$comments = null;
|
||||
$teams = null;
|
||||
|
||||
if ($this->isGranted('edit', $project)) {
|
||||
$commentForm = $this->getCommentForm($project, new ProjectComment())->createView();
|
||||
|
||||
if ($this->isGranted('create_team')) {
|
||||
$defaultTeam = $teamRepository->findOneBy(['name' => $project->getName()]);
|
||||
}
|
||||
if ($this->isGranted('edit', $project) && $this->isGranted('create_team')) {
|
||||
$defaultTeam = $teamRepository->findOneBy(['name' => $project->getName()]);
|
||||
}
|
||||
|
||||
if ($this->isGranted('budget', $project)) {
|
||||
@@ -289,6 +285,10 @@ final class ProjectController extends AbstractController
|
||||
$comments = $this->repository->getComments($project);
|
||||
}
|
||||
|
||||
if ($this->isGranted('comments_create', $project)) {
|
||||
$commentForm = $this->getCommentForm($project, new ProjectComment())->createView();
|
||||
}
|
||||
|
||||
if ($this->isGranted('permissions', $project) || $this->isGranted('details', $project) || $this->isGranted('view_team')) {
|
||||
$teams = $project->getTeams();
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ class CustomerVoter extends AbstractVoter
|
||||
'delete',
|
||||
'permissions',
|
||||
'comments',
|
||||
'comments_create',
|
||||
'details',
|
||||
];
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ class ProjectVoter extends AbstractVoter
|
||||
'delete',
|
||||
'permissions',
|
||||
'comments',
|
||||
'comments_create',
|
||||
'details',
|
||||
];
|
||||
|
||||
|
||||
@@ -107,35 +107,35 @@
|
||||
<td>{{ customer.vatId }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if can_edit %}
|
||||
<tr>
|
||||
<th>{{ 'label.fixedRate'|trans }}</th>
|
||||
<td>
|
||||
{% if customer.fixedRate is not empty %}
|
||||
{{ customer.fixedRate|money(customer.currency) }}
|
||||
{% else %}
|
||||
–
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ 'label.hourlyRate'|trans }}</th>
|
||||
<td>
|
||||
{% if customer.hourlyRate is not empty %}
|
||||
{{ customer.hourlyRate|money(customer.currency) }}
|
||||
{% else %}
|
||||
–
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% for metaField in customer.visibleMetaFields %}
|
||||
<tr>
|
||||
<th>{{ metaField.label }}</th>
|
||||
<td>{{ widgets.form_type_value(metaField.type, metaField.value, customer) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if can_edit %}
|
||||
<tr>
|
||||
<th>{{ 'label.fixedRate'|trans }}</th>
|
||||
<td>
|
||||
{% if customer.fixedRate is not empty %}
|
||||
{{ customer.fixedRate|money(customer.currency) }}
|
||||
{% else %}
|
||||
–
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ 'label.hourlyRate'|trans }}</th>
|
||||
<td>
|
||||
{% if customer.hourlyRate is not empty %}
|
||||
{{ customer.hourlyRate|money(customer.currency) }}
|
||||
{% else %}
|
||||
–
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% for metaField in customer.visibleMetaFields %}
|
||||
<tr>
|
||||
<th>{{ metaField.label }}</th>
|
||||
<td>{{ widgets.form_type_value(metaField.type, metaField.value, customer) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endblock %}
|
||||
{% endembed %}
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
{{ tables.datatable_header(tableName, columns, query, {'reload': 'kimai.customerUpdate kimai.customerTeamUpdate'}) }}
|
||||
|
||||
{% for entry in entries %}
|
||||
<tr class="alternative-link open-edit" data-href="{{ path('customer_details', {'id': entry.id}) }}">
|
||||
<tr{% if is_granted('view', entry) %} class="alternative-link open-edit" data-href="{{ path('customer_details', {'id': entry.id}) }}"{% endif %}>
|
||||
<td>
|
||||
{{ widgets.label_color_dot('customer', true, entry.name, null, entry.color) }}
|
||||
</td>
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
<span class="text-muted pull-right">
|
||||
{% if route_pin is not null %}
|
||||
<a href="{{ path(route_pin, {'id': comment.id}) }}" class="btn btn-default btn-xs {% if comment.pinned %}active{% endif %}"><i class="{{ 'pin'|icon }}"></i></a>
|
||||
{% elseif comment.pinned %}
|
||||
<i class="{{ 'pin'|icon }}"></i>
|
||||
{% endif %}
|
||||
{% if route_delete is not null %}
|
||||
<a href="{{ path(route_delete, {'id': comment.id}) }}" class="confirmation-link btn btn-default btn-xs" data-question="confirm.delete"><i class="{{ 'delete'|icon }}"></i></a>
|
||||
|
||||
@@ -81,35 +81,35 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% if can_edit %}
|
||||
<tr>
|
||||
<th>{{ 'label.fixedRate'|trans }}</th>
|
||||
<td>
|
||||
{% if project.fixedRate is not empty %}
|
||||
{{ project.fixedRate|money(project.customer.currency) }}
|
||||
{% else %}
|
||||
–
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ 'label.hourlyRate'|trans }}</th>
|
||||
<td>
|
||||
{% if project.hourlyRate is not empty %}
|
||||
{{ project.hourlyRate|money(project.customer.currency) }}
|
||||
{% else %}
|
||||
–
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% for metaField in project.visibleMetaFields %}
|
||||
<tr>
|
||||
<th>{{ metaField.label }}</th>
|
||||
<td>{{ widgets.form_type_value(metaField.type, metaField.value, project) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if can_edit %}
|
||||
<tr>
|
||||
<th>{{ 'label.fixedRate'|trans }}</th>
|
||||
<td>
|
||||
{% if project.fixedRate is not empty %}
|
||||
{{ project.fixedRate|money(project.customer.currency) }}
|
||||
{% else %}
|
||||
–
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ 'label.hourlyRate'|trans }}</th>
|
||||
<td>
|
||||
{% if project.hourlyRate is not empty %}
|
||||
{{ project.hourlyRate|money(project.customer.currency) }}
|
||||
{% else %}
|
||||
–
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% for metaField in project.visibleMetaFields %}
|
||||
<tr>
|
||||
<th>{{ metaField.label }}</th>
|
||||
<td>{{ widgets.form_type_value(metaField.type, metaField.value, project) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endblock %}
|
||||
{% endembed %}
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
{{ tables.datatable_header(tableName, columns, query, {'reload': 'kimai.projectUpdate kimai.projectTeamUpdate'}) }}
|
||||
|
||||
{% for entry in entries %}
|
||||
<tr class="alternative-link open-edit" data-href="{{ path('project_details', {'id': entry.id}) }}">
|
||||
<tr{% if is_granted('view', entry) %} class="alternative-link open-edit" data-href="{{ path('project_details', {'id': entry.id}) }}"{% endif %}>
|
||||
<td>{{ widgets.label_color_dot('project', true, entry.name, null, entry.color) }}</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'customer') }}">
|
||||
{{ widgets.label_customer(entry.customer) }}
|
||||
|
||||
@@ -29,7 +29,7 @@ class PermissionControllerTest extends ControllerBaseTest
|
||||
$client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN);
|
||||
$this->assertAccessIsGranted($client, '/admin/permissions');
|
||||
$this->assertHasDataTable($client);
|
||||
$this->assertDataTableRowCount($client, 'datatable_user_admin_permissions', 101);
|
||||
$this->assertDataTableRowCount($client, 'datatable_user_admin_permissions', 107);
|
||||
$this->assertPageActions($client, [
|
||||
'back' => $this->createUrl('/admin/user/'),
|
||||
'roles modal-ajax-form' => $this->createUrl('/admin/permissions/roles/create'),
|
||||
|
||||
Reference in New Issue
Block a user