]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6495 WS permissions/search_templates search for permission templates
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Thu, 3 Sep 2015 16:44:05 +0000 (18:44 +0200)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Fri, 4 Sep 2015 14:10:57 +0000 (16:10 +0200)
25 files changed:
server/sonar-server/src/main/java/org/sonar/server/permission/PermissionTemplateService.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionDependenciesFinder.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionsWsModule.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchProjectPermissionsAction.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchProjectPermissionsData.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchProjectPermissionsDataLoader.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchTemplatesAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchTemplatesData.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchTemplatesDataLoader.java [new file with mode: 0644]
server/sonar-server/src/main/resources/org/sonar/server/permission/ws/search_templates-example.json [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/i18n/I18nRule.java
server/sonar-server/src/test/java/org/sonar/server/permission/PermissionTemplateServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/ws/PermissionsWsModuleTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/ws/SearchProjectPermissionsActionTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/ws/SearchTemplatesActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/permission/ws/SearchTemplatesActionTest/empty.json [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/util/Uuids.java
sonar-db/src/main/java/org/sonar/db/permission/CountByTemplateAndPermissionDto.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/permission/PermissionRepository.java
sonar-db/src/main/java/org/sonar/db/permission/PermissionTemplateDao.java
sonar-db/src/main/java/org/sonar/db/permission/PermissionTemplateMapper.java
sonar-db/src/main/resources/org/sonar/db/permission/PermissionTemplateMapper.xml
sonar-db/src/test/java/org/sonar/db/permission/PermissionTemplateDaoTest.java
sonar-ws/src/main/gen-java/org/sonarqube/ws/Permissions.java
sonar-ws/src/main/protobuf/ws-permissions.proto

index fb438d2d95295fe0af3883b3fab5e3ebc275ae60..a7bb6b0e8ca738b734c8b53a8565f28611c66e7b 100644 (file)
@@ -86,7 +86,7 @@ public class PermissionTemplateService {
   public List<PermissionTemplate> selectAllPermissionTemplates(@Nullable String componentKey) {
     checkProjectAdminUserByComponentKey(userSession, componentKey);
     List<PermissionTemplate> permissionTemplates = Lists.newArrayList();
-    List<PermissionTemplateDto> permissionTemplateDtos = permissionTemplateDao.selectAllPermissionTemplates();
+    List<PermissionTemplateDto> permissionTemplateDtos = permissionTemplateDao.selectAll();
     if (permissionTemplateDtos != null) {
       for (PermissionTemplateDto permissionTemplateDto : permissionTemplateDtos) {
         permissionTemplates.add(PermissionTemplate.create(permissionTemplateDto));
index 5faf1d2dbeff1d774bb629cb8529213bf6cebb1e..f7670aeb0cfc6a428a8a1a933752c091af56e1b5 100644 (file)
@@ -56,7 +56,7 @@ public class PermissionDependenciesFinder {
     return Optional.of(componentFinder.getProjectByUuidOrKey(dbSession, wsProjectRef.uuid(), wsProjectRef.key()));
   }
 
-  public ComponentDto getProject(DbSession dbSession, WsProjectRef projectRef) {
+  ComponentDto getProject(DbSession dbSession, WsProjectRef projectRef) {
     return componentFinder.getProjectByUuidOrKey(dbSession, projectRef.uuid(), projectRef.key());
   }
 
index 0ea55bb75986a2227f6049320019b6f951ec38f3..9f9ed0213dc7d4b9d47bfd1e1060ee6a4f455596 100644 (file)
@@ -45,9 +45,11 @@ public class PermissionsWsModule extends Module {
       DeleteTemplateAction.class,
       ApplyTemplateAction.class,
       SetDefaultTemplateAction.class,
+      SearchTemplatesAction.class,
       // utility classes
       PermissionChangeBuilder.class,
       SearchProjectPermissionsDataLoader.class,
+      SearchTemplatesDataLoader.class,
       PermissionDependenciesFinder.class,
       DefaultPermissionTemplateFinder.class);
   }
index 0276ab8d8a10b0593541443d571fba0b0c297058..bf3cdde8ca7481fca83d2f46ec72d0ac743418ad 100644 (file)
@@ -79,7 +79,7 @@ public class SearchProjectPermissionsAction implements PermissionsWsAction {
     DbSession dbSession = dbClient.openSession(false);
     try {
       SearchProjectPermissionsData data = dataLoader.load(wsRequest);
-      SearchProjectPermissionsResponse response = buildReponse(data);
+      SearchProjectPermissionsResponse response = buildResponse(data);
       writeProtobuf(response, wsRequest, wsResponse);
     } finally {
       dbClient.closeSession(dbSession);
@@ -101,7 +101,7 @@ public class SearchProjectPermissionsAction implements PermissionsWsAction {
     }
   }
 
-  private SearchProjectPermissionsResponse buildReponse(SearchProjectPermissionsData data) {
+  private SearchProjectPermissionsResponse buildResponse(SearchProjectPermissionsData data) {
     SearchProjectPermissionsResponse.Builder response = SearchProjectPermissionsResponse.newBuilder();
     Permission.Builder permissionResponse = Permission.newBuilder();
 
index fd3308b3db7d5a77c0a0db2ea05827aac71bf9ee..529bc28e364d6b64fd622daddd8751c3e8e92ef3 100644 (file)
@@ -34,7 +34,7 @@ import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.ImmutableList.copyOf;
 import static com.google.common.collect.ImmutableTable.copyOf;
 
-public class SearchProjectPermissionsData {
+class SearchProjectPermissionsData {
   private final List<ComponentDto> rootComponents;
   private final Paging paging;
   private final Table<Long, String, Integer> userCountByProjectIdAndPermission;
@@ -47,27 +47,27 @@ public class SearchProjectPermissionsData {
     this.groupCountByProjectIdAndPermission = copyOf(builder.groupCountByProjectIdAndPermission);
   }
 
-  public static Builder newBuilder() {
+  static Builder newBuilder() {
     return new Builder();
   }
 
-  public List<ComponentDto> rootComponents() {
+  List<ComponentDto> rootComponents() {
     return rootComponents;
   }
 
-  public Paging paging() {
+  Paging paging() {
     return paging;
   }
 
-  public int userCount(long rootComponentId, String permission) {
+  int userCount(long rootComponentId, String permission) {
     return firstNonNull(userCountByProjectIdAndPermission.get(rootComponentId, permission), 0);
   }
 
-  public int groupCount(long rootComponentId, String permission) {
+  int groupCount(long rootComponentId, String permission) {
     return firstNonNull(groupCountByProjectIdAndPermission.get(rootComponentId, permission), 0);
   }
 
-  public Set<String> permissions(long rootComponentId) {
+  Set<String> permissions(long rootComponentId) {
     return FluentIterable.from(
       Iterables.concat(
         userCountByProjectIdAndPermission.row(rootComponentId).keySet(),
@@ -76,7 +76,7 @@ public class SearchProjectPermissionsData {
       ).toSortedSet(Ordering.natural());
   }
 
-  public static class Builder {
+  static class Builder {
     private List<ComponentDto> projects;
     private Paging paging;
     private Table<Long, String, Integer> userCountByProjectIdAndPermission;
@@ -86,7 +86,7 @@ public class SearchProjectPermissionsData {
       // prevents instantiation outside main class
     }
 
-    public SearchProjectPermissionsData build() {
+    SearchProjectPermissionsData build() {
       checkState(projects != null);
       checkState(userCountByProjectIdAndPermission != null);
       checkState(groupCountByProjectIdAndPermission != null);
@@ -94,22 +94,22 @@ public class SearchProjectPermissionsData {
       return new SearchProjectPermissionsData(this);
     }
 
-    public Builder rootComponents(List<ComponentDto> projects) {
+    Builder rootComponents(List<ComponentDto> projects) {
       this.projects = projects;
       return this;
     }
 
-    public Builder paging(Paging paging) {
+    Builder paging(Paging paging) {
       this.paging = paging;
       return this;
     }
 
-    public Builder userCountByProjectIdAndPermission(Table<Long, String, Integer> userCountByProjectIdAndPermission) {
+    Builder userCountByProjectIdAndPermission(Table<Long, String, Integer> userCountByProjectIdAndPermission) {
       this.userCountByProjectIdAndPermission = userCountByProjectIdAndPermission;
       return this;
     }
 
-    public Builder groupCountByProjectIdAndPermission(Table<Long, String, Integer> groupCountByProjectIdAndPermission) {
+    Builder groupCountByProjectIdAndPermission(Table<Long, String, Integer> groupCountByProjectIdAndPermission) {
       this.groupCountByProjectIdAndPermission = groupCountByProjectIdAndPermission;
       return this;
     }
index 208171d34f0d966a5ce197430b5b649e3a248fb0..a3785a785984993eefc3648b8c21674faa695e4f 100644 (file)
@@ -38,7 +38,6 @@ import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.permission.CountByProjectAndPermissionDto;
-import org.sonar.server.component.ComponentFinder;
 
 import static java.util.Collections.singletonList;
 import static org.sonar.api.server.ws.WebService.Param.PAGE;
@@ -50,12 +49,12 @@ import static org.sonar.server.permission.ws.SearchProjectPermissionsData.newBui
 
 public class SearchProjectPermissionsDataLoader {
   private final DbClient dbClient;
-  private final ComponentFinder componentFinder;
+  private final PermissionDependenciesFinder finder;
   private final Collection<String> rootQualifiers;
 
-  public SearchProjectPermissionsDataLoader(DbClient dbClient, ComponentFinder componentFinder, ResourceTypes resourceTypes) {
+  public SearchProjectPermissionsDataLoader(DbClient dbClient, PermissionDependenciesFinder finder, ResourceTypes resourceTypes) {
     this.dbClient = dbClient;
-    this.componentFinder = componentFinder;
+    this.finder = finder;
     this.rootQualifiers = Collections2.transform(resourceTypes.getRoots(), RESOURCE_TYPE_TO_QUALIFIER);
   }
 
@@ -93,7 +92,7 @@ public class SearchProjectPermissionsDataLoader {
     Optional<WsProjectRef> project = WsProjectRef.optionalFromRequest(wsRequest);
 
     if (project.isPresent()) {
-      return singletonList(componentFinder.getProjectByUuidOrKey(dbSession, project.get().uuid(), project.get().key()));
+      return singletonList(finder.getProject(dbSession, project.get()));
     }
 
     return dbClient.componentDao().selectComponents(dbSession, rootQualifiers, paging.offset(), paging.pageSize(), query);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchTemplatesAction.java b/server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchTemplatesAction.java
new file mode 100644 (file)
index 0000000..8569eb9
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.permission.ws;
+
+import org.sonar.api.i18n.I18n;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.core.permission.ProjectPermissions;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.permission.PermissionTemplateDto;
+import org.sonar.server.user.UserSession;
+import org.sonarqube.ws.Permissions.Permission;
+import org.sonarqube.ws.Permissions.PermissionTemplate;
+import org.sonarqube.ws.Permissions.SearchTemplatesResponse;
+
+import static org.sonar.api.utils.DateUtils.formatDateTime;
+import static org.sonar.server.permission.PermissionPrivilegeChecker.checkGlobalAdminUser;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
+
+public class SearchTemplatesAction implements PermissionsWsAction {
+  private static final String PROPERTY_PREFIX = "projects_role.";
+  private static final String DESCRIPTION_SUFFIX = ".desc";
+
+  private final DbClient dbClient;
+  private final UserSession userSession;
+  private final I18n i18n;
+  private final SearchTemplatesDataLoader dataLoader;
+
+  public SearchTemplatesAction(DbClient dbClient, UserSession userSession, I18n i18n, SearchTemplatesDataLoader dataLoader) {
+    this.dbClient = dbClient;
+    this.userSession = userSession;
+    this.i18n = i18n;
+    this.dataLoader = dataLoader;
+  }
+
+  @Override
+  public void define(WebService.NewController context) {
+    context.createAction("search_templates")
+      .setDescription("List permission templates.<br />" +
+        "It requires administration permissions to access.")
+      .setResponseExample(getClass().getResource("search_templates-example.json"))
+      .setSince("5.2")
+      .addSearchQuery("defau", "permission template names")
+      .setHandler(this);
+  }
+
+  @Override
+  public void handle(Request wsRequest, Response wsResponse) throws Exception {
+    checkGlobalAdminUser(userSession);
+
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      SearchTemplatesData data = dataLoader.load(wsRequest);
+      SearchTemplatesResponse response = buildResponse(data);
+      writeProtobuf(response, wsRequest, wsResponse);
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  private SearchTemplatesResponse buildResponse(SearchTemplatesData data) {
+    SearchTemplatesResponse.Builder response = SearchTemplatesResponse.newBuilder();
+    Permission.Builder permissionResponse = Permission.newBuilder();
+
+    PermissionTemplate.Builder templateBuilder = PermissionTemplate.newBuilder();
+    for (PermissionTemplateDto templateDto : data.templates()) {
+      templateBuilder
+        .clear()
+        .setId(templateDto.getUuid())
+        .setName(templateDto.getName())
+        .setCreatedAt(formatDateTime(templateDto.getCreatedAt()))
+        .setUpdatedAt(formatDateTime(templateDto.getUpdatedAt()));
+      if (templateDto.getKeyPattern() != null) {
+        templateBuilder.setProjectKeyPattern(templateDto.getKeyPattern());
+      }
+      if (templateDto.getDescription() != null) {
+        templateBuilder.setDescription(templateDto.getDescription());
+      }
+      for (String permission : data.permissions(templateDto.getId())) {
+        templateBuilder.addPermissions(
+          permissionResponse
+            .clear()
+            .setKey(permission)
+            .setUsersCount(data.userCount(templateDto.getId(), permission))
+            .setGroupsCount(data.groupCount(templateDto.getId(), permission)));
+      }
+      response.addPermissionTemplates(templateBuilder);
+    }
+
+    for (String permissionKey : ProjectPermissions.ALL) {
+      response.addPermissions(
+        permissionResponse
+          .clear()
+          .setKey(permissionKey)
+          .setName(i18nName(permissionKey))
+          .setDescription(i18nDescriptionMessage(permissionKey))
+        );
+    }
+
+    return response.build();
+  }
+
+  private String i18nDescriptionMessage(String permissionKey) {
+    return i18n.message(userSession.locale(), PROPERTY_PREFIX + permissionKey + DESCRIPTION_SUFFIX, "");
+  }
+
+  private String i18nName(String permissionKey) {
+    return i18n.message(userSession.locale(), PROPERTY_PREFIX + permissionKey, permissionKey);
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchTemplatesData.java b/server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchTemplatesData.java
new file mode 100644 (file)
index 0000000..5ef2640
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.permission.ws;
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Table;
+import java.util.List;
+import java.util.Set;
+import org.sonar.db.permission.PermissionTemplateDto;
+
+import static com.google.common.base.Objects.firstNonNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.ImmutableList.copyOf;
+import static com.google.common.collect.ImmutableTable.copyOf;
+import static com.google.common.collect.Ordering.natural;
+
+class SearchTemplatesData {
+  private final List<PermissionTemplateDto> paginatedTemplates;
+  private final Table<Long, String, Integer> userCountByTemplateIdAndPermission;
+  private final Table<Long, String, Integer> groupCountByTemplateIdAndPermission;
+
+  private SearchTemplatesData(Builder builder) {
+    this.paginatedTemplates = copyOf(builder.templates);
+    this.userCountByTemplateIdAndPermission = copyOf(builder.userCountByTemplateIdAndPermission);
+    this.groupCountByTemplateIdAndPermission = copyOf(builder.groupCountByTemplateIdAndPermission);
+  }
+
+  public static Builder newBuilder() {
+    return new Builder();
+  }
+
+  public List<PermissionTemplateDto> templates() {
+    return paginatedTemplates;
+  }
+
+  public int userCount(long templateId, String permission) {
+    return firstNonNull(userCountByTemplateIdAndPermission.get(templateId, permission), 0);
+  }
+
+  public int groupCount(long templateId, String permission) {
+    return firstNonNull(groupCountByTemplateIdAndPermission.get(templateId, permission), 0);
+  }
+
+  public Set<String> permissions(long templateId) {
+    return FluentIterable.from(
+      Iterables.concat(
+        userCountByTemplateIdAndPermission.row(templateId).keySet(),
+        groupCountByTemplateIdAndPermission.row(templateId).keySet()
+        )
+      ).toSortedSet(natural());
+  }
+
+  public static class Builder {
+    private List<PermissionTemplateDto> templates;
+    private Table<Long, String, Integer> userCountByTemplateIdAndPermission;
+    private Table<Long, String, Integer> groupCountByTemplateIdAndPermission;
+
+    private Builder() {
+      // prevents instantiation outside main class
+    }
+
+    public SearchTemplatesData build() {
+      checkState(templates != null);
+      checkState(userCountByTemplateIdAndPermission != null);
+      checkState(groupCountByTemplateIdAndPermission != null);
+
+      return new SearchTemplatesData(this);
+    }
+
+    public Builder templates(List<PermissionTemplateDto> templates) {
+      this.templates = templates;
+      return this;
+    }
+
+    public Builder userCountByTemplateIdAndPermission(Table<Long, String, Integer> userCountByTemplateIdAndPermission) {
+      this.userCountByTemplateIdAndPermission = userCountByTemplateIdAndPermission;
+      return this;
+    }
+
+    public Builder groupCountByTemplateIdAndPermission(Table<Long, String, Integer> groupCountByTemplateIdAndPermission) {
+      this.groupCountByTemplateIdAndPermission = groupCountByTemplateIdAndPermission;
+      return this;
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchTemplatesDataLoader.java b/server/sonar-server/src/main/java/org/sonar/server/permission/ws/SearchTemplatesDataLoader.java
new file mode 100644 (file)
index 0000000..f6cce2b
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.permission.ws;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Table;
+import com.google.common.collect.TreeBasedTable;
+import java.util.List;
+import javax.annotation.Nonnull;
+import org.apache.ibatis.session.ResultContext;
+import org.apache.ibatis.session.ResultHandler;
+import org.sonar.api.server.ws.Request;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.permission.CountByTemplateAndPermissionDto;
+import org.sonar.db.permission.PermissionTemplateDto;
+
+import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY;
+import static org.sonar.server.permission.ws.SearchTemplatesData.newBuilder;
+
+public class SearchTemplatesDataLoader {
+  private final DbClient dbClient;
+
+  public SearchTemplatesDataLoader(DbClient dbClient) {
+    this.dbClient = dbClient;
+  }
+
+  public SearchTemplatesData load(Request wsRequest) {
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      SearchTemplatesData.Builder data = newBuilder();
+      List<PermissionTemplateDto> templates = searchTemplates(dbSession, wsRequest);
+      List<Long> templateIds = Lists.transform(templates, TemplateToIdFunction.INSTANCE);
+
+      data.templates(templates)
+        .userCountByTemplateIdAndPermission(userCountByTemplateIdAndPermission(dbSession, templateIds))
+        .groupCountByTemplateIdAndPermission(groupCountByTemplateIdAndPermission(dbSession, templateIds));
+
+      return data.build();
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  private List<PermissionTemplateDto> searchTemplates(DbSession dbSession, Request wsRequest) {
+    String nameMatch = wsRequest.param(TEXT_QUERY);
+
+    return nameMatch == null ?
+      dbClient.permissionTemplateDao().selectAll(dbSession)
+      : dbClient.permissionTemplateDao().selectAll(dbSession, nameMatch);
+  }
+
+  private Table<Long, String, Integer> userCountByTemplateIdAndPermission(DbSession dbSession, List<Long> templateIds) {
+    final Table<Long, String, Integer> userCountByTemplateIdAndPermission = TreeBasedTable.create();
+
+    dbClient.permissionTemplateDao().usersCountByTemplateIdAndPermission(dbSession, templateIds, new ResultHandler() {
+      @Override
+      public void handleResult(ResultContext context) {
+        CountByTemplateAndPermissionDto row = (CountByTemplateAndPermissionDto) context.getResultObject();
+        userCountByTemplateIdAndPermission.put(row.getTemplateId(), row.getPermission(), row.getCount());
+      }
+    });
+
+    return userCountByTemplateIdAndPermission;
+  }
+
+  private Table<Long, String, Integer> groupCountByTemplateIdAndPermission(DbSession dbSession, List<Long> templateIds) {
+    final Table<Long, String, Integer> userCountByTemplateIdAndPermission = TreeBasedTable.create();
+
+    dbClient.permissionTemplateDao().groupsCountByTemplateIdAndPermission(dbSession, templateIds, new ResultHandler() {
+      @Override
+      public void handleResult(ResultContext context) {
+        CountByTemplateAndPermissionDto row = (CountByTemplateAndPermissionDto) context.getResultObject();
+        userCountByTemplateIdAndPermission.put(row.getTemplateId(), row.getPermission(), row.getCount());
+      }
+    });
+
+    return userCountByTemplateIdAndPermission;
+  }
+
+  private enum TemplateToIdFunction implements Function<PermissionTemplateDto, Long> {
+    INSTANCE;
+
+    @Override
+    public Long apply(@Nonnull PermissionTemplateDto template) {
+      return template.getId();
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/permission/ws/search_templates-example.json b/server/sonar-server/src/main/resources/org/sonar/server/permission/ws/search_templates-example.json
new file mode 100644 (file)
index 0000000..bfdcf08
--- /dev/null
@@ -0,0 +1,84 @@
+{
+  "permissionTemplates": [
+    {
+      "id": "AU-TpxcA-iU5OvuD2FL0",
+      "name": "Default template for Developers",
+      "projectKeyPattern": ".*sonar.developer.*",
+      "createdAt": "2004-11-15T07:26:40+0100",
+      "updatedAt": "2004-11-19T22:33:20+0100",
+      "permissions": [
+        {
+          "key": "user",
+          "usersCount": 0,
+          "groupsCount": 1
+        }
+      ]
+    },
+    {
+      "id": "AU-Tpxb--iU5OvuD2FLy",
+      "name": "Default template for Projects",
+      "description": "Template for new projects",
+      "createdAt": "2001-09-09T03:46:40+0200",
+      "updatedAt": "2001-09-09T03:46:40+0200",
+      "permissions": [
+        {
+          "key": "admin",
+          "usersCount": 0,
+          "groupsCount": 1
+        },
+        {
+          "key": "codeviewer",
+          "usersCount": 1,
+          "groupsCount": 0
+        },
+        {
+          "key": "issueadmin",
+          "usersCount": 3,
+          "groupsCount": 0
+        }
+      ]
+    },
+    {
+      "id": "AU-TpxcA-iU5OvuD2FLz",
+      "name": "Default template for Views",
+      "description": "Template for new views",
+      "projectKeyPattern": ".*sonar.views.*",
+      "createdAt": "2001-09-09T03:46:40+0200",
+      "updatedAt": "2004-11-09T12:33:20+0100",
+      "permissions": [
+        {
+          "key": "issueadmin",
+          "usersCount": 0,
+          "groupsCount": 3
+        },
+        {
+          "key": "user",
+          "usersCount": 2,
+          "groupsCount": 0
+        }
+      ]
+    }
+  ],
+  "permissions": [
+    {
+      "key": "user",
+      "name": "Browse",
+      "description": "Ability to access a project, browse its measures, and create/edit issues for it."
+    },
+    {
+      "key": "admin",
+      "name": "Administer",
+      "description": "Ability to access project settings and perform administration tasks. (Users will also need \"Browse\" permission)"
+    },
+    {
+      "key": "issueadmin",
+      "name": "Administer Issues",
+      "description": "Grants the permission to perform advanced editing on issues: marking an issue False Positive / Won\u0027t Fix or changing an Issue\u0027s severity. (Users will also need \"Browse\" permission)"
+    },
+    {
+      "key": "codeviewer",
+      "name": "See Source Code",
+      "description": "Ability to view the project\u0027s source code. (Users will also need \"Browse\" permission)"
+    }
+  ]
+}
index 682184d95bcdd20305923ae5420fd2228ed5a32b..1e82571f9707019973cfd188c918f5339df5e907 100644 (file)
@@ -37,6 +37,19 @@ public class I18nRule implements I18n {
     return this;
   }
 
+  public void setProjectPermissions() {
+    put("projects_role.admin", "Administer");
+    put("projects_role.admin.desc", "Ability to access project settings and perform administration tasks. " +
+      "(Users will also need \"Browse\" permission)");
+    put("projects_role.issueadmin", "Administer Issues");
+    put("projects_role.issueadmin.desc", "Grants the permission to perform advanced editing on issues: marking an issue " +
+      "False Positive / Won't Fix or changing an Issue's severity. (Users will also need \"Browse\" permission)");
+    put("projects_role.user", "Browse");
+    put("projects_role.user.desc", "Ability to access a project, browse its measures, and create/edit issues for it.");
+    put("projects_role.codeviewer", "See Source Code");
+    put("projects_role.codeviewer.desc", "Ability to view the project's source code. (Users will also need \"Browse\" permission)");
+  }
+
   @Override
   public String message(Locale locale, String key, @Nullable String defaultValue, Object... parameters) {
     String messageInMap = messages.get(key);
index 6dd8aab018512718c0deff3fba86f616ceb66df2..ee96af34b579e750b4fcf176434c0c9248e1253f 100644 (file)
@@ -195,7 +195,7 @@ public class PermissionTemplateServiceTest {
       new PermissionTemplateDto().setId(1L).setName("template1").setDescription("template1");
     PermissionTemplateDto template2 =
       new PermissionTemplateDto().setId(2L).setName("template2").setDescription("template2");
-    when(permissionTemplateDao.selectAllPermissionTemplates()).thenReturn(Lists.newArrayList(template1, template2));
+    when(permissionTemplateDao.selectAll()).thenReturn(Lists.newArrayList(template1, template2));
 
     List<PermissionTemplate> templates = underTest.selectAllPermissionTemplates();
 
@@ -213,7 +213,7 @@ public class PermissionTemplateServiceTest {
       new PermissionTemplateDto().setId(1L).setName("template1").setDescription("template1");
     PermissionTemplateDto template2 =
       new PermissionTemplateDto().setId(2L).setName("template2").setDescription("template2");
-    when(permissionTemplateDao.selectAllPermissionTemplates()).thenReturn(Lists.newArrayList(template1, template2));
+    when(permissionTemplateDao.selectAll()).thenReturn(Lists.newArrayList(template1, template2));
 
     List<PermissionTemplate> templates = underTest.selectAllPermissionTemplates("org.sample.Sample");
 
@@ -249,7 +249,7 @@ public class PermissionTemplateServiceTest {
     expected.expectMessage("The 'projectKeyPattern' parameter must be a valid Java regular expression. '[azerty' was passed");
 
     PermissionTemplateDto template1 = new PermissionTemplateDto().setId(1L).setName("template1").setDescription("template1");
-    when(permissionTemplateDao.selectAllPermissionTemplates()).thenReturn(Lists.newArrayList(template1));
+    when(permissionTemplateDao.selectAll()).thenReturn(Lists.newArrayList(template1));
 
     underTest.updatePermissionTemplate(1L, "template1", "template1", "[azerty");
   }
@@ -260,7 +260,7 @@ public class PermissionTemplateServiceTest {
       new PermissionTemplateDto().setId(1L).setName("template1").setDescription("template1");
     PermissionTemplateDto template2 =
       new PermissionTemplateDto().setId(2L).setName("template2").setDescription("template2");
-    when(permissionTemplateDao.selectAllPermissionTemplates()).thenReturn(Lists.newArrayList(template1, template2));
+    when(permissionTemplateDao.selectAll()).thenReturn(Lists.newArrayList(template1, template2));
 
     underTest.updatePermissionTemplate(1L, "template1", "new_description", null);
 
index d00e32fbc6b13507798c15f44876f70d469de4a9..fb380680cc4d922a47098259570c6be4d53ed71d 100644 (file)
@@ -30,6 +30,6 @@ public class PermissionsWsModuleTest {
   public void verify_count_of_added_components() {
     ComponentContainer container = new ComponentContainer();
     new PermissionsWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(24);
+    assertThat(container.size()).isEqualTo(26);
   }
 }
index 3cf1281ca5d541e0d1c761b5d21101aafd987445..95f36fd1ce3d4662f03384712b434d7a859f989f 100644 (file)
@@ -85,9 +85,10 @@ public class SearchProjectPermissionsActionTest {
     resourceTypes = mock(ResourceTypes.class);
     when(resourceTypes.getRoots()).thenReturn(rootResourceTypes());
     ComponentFinder componentFinder = new ComponentFinder(dbClient);
-    initI18nMessages();
+    PermissionDependenciesFinder finder = new PermissionDependenciesFinder(dbClient, componentFinder);
+    i18n.setProjectPermissions();
 
-    dataLoader = new SearchProjectPermissionsDataLoader(dbClient, componentFinder, resourceTypes);
+    dataLoader = new SearchProjectPermissionsDataLoader(dbClient, finder, resourceTypes);
     underTest = new SearchProjectPermissionsAction(dbClient, userSession, i18n, dataLoader);
 
     ws = new WsActionTester(underTest);
@@ -224,7 +225,7 @@ public class SearchProjectPermissionsActionTest {
     insertComponent(newDeveloper("developer-name"));
     insertComponent(newProjectDto("project-uuid"));
     commit();
-    dataLoader = new SearchProjectPermissionsDataLoader(dbClient, new ComponentFinder(dbClient), resourceTypes);
+    dataLoader = new SearchProjectPermissionsDataLoader(dbClient, new PermissionDependenciesFinder(dbClient, new ComponentFinder(dbClient)), resourceTypes);
     underTest = new SearchProjectPermissionsAction(dbClient, userSession, i18n, dataLoader);
     ws = new WsActionTester(underTest);
 
@@ -317,17 +318,4 @@ public class SearchProjectPermissionsActionTest {
 
     return asList(project, view, dev);
   }
-
-  private void initI18nMessages() {
-    i18n.put("projects_role.admin", "Administer");
-    i18n.put("projects_role.admin.desc", "Ability to access project settings and perform administration tasks. " +
-      "(Users will also need \"Browse\" permission)");
-    i18n.put("projects_role.issueadmin", "Administer Issues");
-    i18n.put("projects_role.issueadmin.desc", "Grants the permission to perform advanced editing on issues: marking an issue " +
-      "False Positive / Won't Fix or changing an Issue's severity. (Users will also need \"Browse\" permission)");
-    i18n.put("projects_role.user", "Browse");
-    i18n.put("projects_role.user.desc", "Ability to access a project, browse its measures, and create/edit issues for it.");
-    i18n.put("projects_role.codeviewer", "See Source Code");
-    i18n.put("projects_role.codeviewer.desc", "Ability to view the project's source code. (Users will also need \"Browse\" permission)");
-  }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/ws/SearchTemplatesActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/ws/SearchTemplatesActionTest.java
new file mode 100644 (file)
index 0000000..2db0f1a
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.permission.ws;
+
+import java.util.Date;
+import javax.annotation.Nullable;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.permission.PermissionTemplateDto;
+import org.sonar.db.user.GroupDto;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.i18n.I18nRule;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.WsActionTester;
+import org.sonar.test.DbTests;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY;
+import static org.sonar.core.permission.GlobalPermissions.QUALITY_PROFILE_ADMIN;
+import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
+import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02;
+import static org.sonar.core.util.Uuids.UUID_EXAMPLE_03;
+import static org.sonar.db.permission.PermissionTemplateTesting.newPermissionTemplateDto;
+import static org.sonar.db.user.GroupTesting.newGroupDto;
+import static org.sonar.db.user.UserTesting.newUserDto;
+import static org.sonar.test.JsonAssert.assertJson;
+
+@Category(DbTests.class)
+public class SearchTemplatesActionTest {
+  @ClassRule
+  public static DbTester db = DbTester.create(System2.INSTANCE);
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  WsActionTester ws;
+  I18nRule i18n = new I18nRule();
+  DbClient dbClient = db.getDbClient();
+  DbSession dbSession = db.getSession();
+  SearchTemplatesDataLoader dataLoader;
+
+  SearchTemplatesAction underTest;
+
+  @Before
+  public void setUp() {
+    db.truncateTables();
+    i18n.setProjectPermissions();
+
+    dataLoader = new SearchTemplatesDataLoader(dbClient);
+    underTest = new SearchTemplatesAction(dbClient, userSession, i18n, dataLoader);
+
+    ws = new WsActionTester(underTest);
+
+    userSession.login().setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+  }
+
+  @Test
+  public void search_project_permissions() {
+    PermissionTemplateDto projectTemplate = insertProjectTemplate();
+    PermissionTemplateDto viewsTemplate = insertViewsTemplate();
+    PermissionTemplateDto developerTemplate = insertDeveloperTemplate();
+
+    UserDto user1 = insertUser(newUserDto());
+    UserDto user2 = insertUser(newUserDto());
+    UserDto user3 = insertUser(newUserDto());
+
+    GroupDto group1 = insertGroup(newGroupDto());
+    GroupDto group2 = insertGroup(newGroupDto());
+    GroupDto group3 = insertGroup(newGroupDto());
+
+    addUserToTemplate(projectTemplate.getId(), user1.getId(), UserRole.ISSUE_ADMIN);
+    addUserToTemplate(projectTemplate.getId(), user2.getId(), UserRole.ISSUE_ADMIN);
+    addUserToTemplate(projectTemplate.getId(), user3.getId(), UserRole.ISSUE_ADMIN);
+    addUserToTemplate(projectTemplate.getId(), user1.getId(), UserRole.CODEVIEWER);
+    addGroupToTemplate(projectTemplate.getId(), group1.getId(), UserRole.ADMIN);
+
+    addUserToTemplate(viewsTemplate.getId(), user1.getId(), UserRole.USER);
+    addUserToTemplate(viewsTemplate.getId(), user2.getId(), UserRole.USER);
+    addGroupToTemplate(viewsTemplate.getId(), group1.getId(), UserRole.ISSUE_ADMIN);
+    addGroupToTemplate(viewsTemplate.getId(), group2.getId(), UserRole.ISSUE_ADMIN);
+    addGroupToTemplate(viewsTemplate.getId(), group3.getId(), UserRole.ISSUE_ADMIN);
+
+    addGroupToTemplate(developerTemplate.getId(), group1.getId(), UserRole.USER);
+
+    commit();
+
+    String result = newRequest();
+
+    assertJson(result)
+      .withStrictArrayOrder()
+      .isSimilarTo(getClass().getResource("search_templates-example.json"));
+  }
+
+  @Test
+  public void empty_result() {
+    String result = newRequest();
+
+    assertJson(result)
+      .withStrictArrayOrder()
+      .isSimilarTo(getClass().getResource("SearchTemplatesActionTest/empty.json"));
+  }
+
+  @Test
+  public void search_by_name() {
+    insertProjectTemplate();
+    insertViewsTemplate();
+    insertDeveloperTemplate();
+    commit();
+
+    String result = ws.newRequest()
+      .setParam(TEXT_QUERY, "views")
+      .execute().getInput();
+
+    assertThat(result).contains("Default template for Views")
+      .doesNotContain("projects")
+      .doesNotContain("developers");
+  }
+
+  @Test
+  public void fail_if_not_logged_in() {
+    expectedException.expect(UnauthorizedException.class);
+    userSession.anonymous();
+
+    ws.newRequest().execute();
+  }
+
+  @Test
+  public void fail_if_not_global_admin() {
+    expectedException.expect(ForbiddenException.class);
+    userSession.login().setGlobalPermissions(QUALITY_PROFILE_ADMIN);
+
+    ws.newRequest().execute();
+  }
+
+  private String newRequest() {
+    return ws.newRequest().execute().getInput();
+  }
+
+  private PermissionTemplateDto insertProjectTemplate() {
+    return insertTemplate(newPermissionTemplateDto()
+      .setUuid(UUID_EXAMPLE_01)
+      .setName("Default template for Projects")
+      .setDescription("Template for new projects")
+      .setKeyPattern(null)
+      .setCreatedAt(new Date(1_000_000_000_000L))
+      .setUpdatedAt(new Date(1_000_000_000_000L)));
+  }
+
+  private PermissionTemplateDto insertViewsTemplate() {
+    return insertTemplate(newPermissionTemplateDto()
+      .setUuid(UUID_EXAMPLE_02)
+      .setName("Default template for Views")
+      .setDescription("Template for new views")
+      .setKeyPattern(".*sonar.views.*")
+      .setCreatedAt(new Date(1_000_000_000_000L))
+      .setUpdatedAt(new Date(1_100_000_000_000L)));
+  }
+
+  private PermissionTemplateDto insertDeveloperTemplate() {
+    return insertTemplate(newPermissionTemplateDto()
+      .setUuid(UUID_EXAMPLE_03)
+      .setName("Default template for Developers")
+      .setKeyPattern(".*sonar.developer.*")
+      .setDescription(null)
+      .setCreatedAt(new Date(1_100_500_000_000L))
+      .setUpdatedAt(new Date(1_100_900_000_000L)));
+  }
+
+  private PermissionTemplateDto insertTemplate(PermissionTemplateDto template) {
+    return dbClient.permissionTemplateDao().insert(dbSession, template);
+  }
+
+  private GroupDto insertGroup(GroupDto groupDto) {
+    return dbClient.groupDao().insert(dbSession, groupDto);
+  }
+
+  private UserDto insertUser(UserDto userDto) {
+    return dbClient.userDao().insert(dbSession, userDto.setActive(true));
+  }
+
+  private void addGroupToTemplate(long templateId, @Nullable Long groupId, String permission) {
+    dbClient.permissionTemplateDao().insertGroupPermission(dbSession, templateId, groupId, permission);
+  }
+
+  private void addUserToTemplate(long templateId, long userId, String permission) {
+    dbClient.permissionTemplateDao().insertUserPermission(dbSession, templateId, userId, permission);
+  }
+
+  private void commit() {
+    dbSession.commit();
+  }
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/permission/ws/SearchTemplatesActionTest/empty.json b/server/sonar-server/src/test/resources/org/sonar/server/permission/ws/SearchTemplatesActionTest/empty.json
new file mode 100644 (file)
index 0000000..ea5874c
--- /dev/null
@@ -0,0 +1,25 @@
+{
+  "permissionTemplates": [],
+  "permissions": [
+    {
+      "key": "user",
+      "name": "Browse",
+      "description": "Ability to access a project, browse its measures, and create/edit issues for it."
+    },
+    {
+      "key": "admin",
+      "name": "Administer",
+      "description": "Ability to access project settings and perform administration tasks. (Users will also need \"Browse\" permission)"
+    },
+    {
+      "key": "issueadmin",
+      "name": "Administer Issues",
+      "description": "Grants the permission to perform advanced editing on issues: marking an issue False Positive / Won't Fix or changing an Issue's severity. (Users will also need \"Browse\" permission)"
+    },
+    {
+      "key": "codeviewer",
+      "name": "See Source Code",
+      "description": "Ability to view the project's source code. (Users will also need \"Browse\" permission)"
+    }
+  ]
+}
index 387b75e1391fca1c5823b60f768548a01deee69a..2db82d0f899db1191ddf4907ad24b6c37a55423c 100644 (file)
@@ -21,6 +21,17 @@ package org.sonar.core.util;
 
 public class Uuids {
 
+  public static final String UUID_EXAMPLE_01 = "AU-Tpxb--iU5OvuD2FLy";
+  public static final String UUID_EXAMPLE_02 = "AU-TpxcA-iU5OvuD2FLz";
+  public static final String UUID_EXAMPLE_03 = "AU-TpxcA-iU5OvuD2FL0";
+  public static final String UUID_EXAMPLE_04 = "AU-TpxcA-iU5OvuD2FL1";
+  public static final String UUID_EXAMPLE_05 = "AU-TpxcA-iU5OvuD2FL2";
+  public static final String UUID_EXAMPLE_06 = "AU-TpxcA-iU5OvuD2FL3";
+  public static final String UUID_EXAMPLE_07 = "AU-TpxcA-iU5OvuD2FL4";
+  public static final String UUID_EXAMPLE_08 = "AU-TpxcA-iU5OvuD2FL5";
+  public static final String UUID_EXAMPLE_09 = "AU-TpxcB-iU5OvuD2FL6";
+  public static final String UUID_EXAMPLE_10 = "AU-TpxcB-iU5OvuD2FL7";
+
   private Uuids() {
     // only static fields
   }
diff --git a/sonar-db/src/main/java/org/sonar/db/permission/CountByTemplateAndPermissionDto.java b/sonar-db/src/main/java/org/sonar/db/permission/CountByTemplateAndPermissionDto.java
new file mode 100644 (file)
index 0000000..4a9d84e
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.db.permission;
+
+public class CountByTemplateAndPermissionDto {
+  private long templateId;
+  private String permission;
+  private int count;
+
+  public long getTemplateId() {
+    return templateId;
+  }
+
+  public void setTemplateId(long templateId) {
+    this.templateId = templateId;
+  }
+
+  public String getPermission() {
+    return permission;
+  }
+
+  public void setPermission(String permission) {
+    this.permission = permission;
+  }
+
+  public int getCount() {
+    return count;
+  }
+
+  public void setCount(int count) {
+    this.count = count;
+  }
+}
index 91deb4473e1e1e24cc40b72633e786e0252bec45..0c7bfacd2375f8a18b63f39f7a76b83da915bf11 100644 (file)
@@ -166,7 +166,7 @@ public class PermissionRepository {
    * permission template for the resource qualifier.
    */
   private String getApplicablePermissionTemplateKey(DbSession session, final String componentKey, String qualifier) {
-    List<PermissionTemplateDto> allPermissionTemplates = dbClient.permissionTemplateDao().selectAllPermissionTemplates(session);
+    List<PermissionTemplateDto> allPermissionTemplates = dbClient.permissionTemplateDao().selectAll(session);
     List<PermissionTemplateDto> matchingTemplates = new ArrayList<>();
     for (PermissionTemplateDto permissionTemplateDto : allPermissionTemplates) {
       String keyPattern = permissionTemplateDto.getKeyPattern();
index 3700d39a1cefe301104d38beaf125bf1c8e27548..f01ebe0566510950902d7bf69d7c4ca997de0854 100644 (file)
 package org.sonar.db.permission;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import org.apache.ibatis.session.ResultHandler;
 import org.apache.ibatis.session.RowBounds;
 import org.apache.ibatis.session.SqlSession;
 import org.sonar.api.security.DefaultGroups;
@@ -35,11 +39,15 @@ import org.sonar.db.DbSession;
 import org.sonar.db.MyBatis;
 
 import static com.google.common.collect.Maps.newHashMap;
+import static java.lang.String.format;
+import static org.sonar.db.DatabaseUtils.executeLargeInputsWithoutOutput;
 
 public class PermissionTemplateDao implements Dao {
 
   public static final String QUERY_PARAMETER = "query";
   public static final String TEMPLATE_ID_PARAMETER = "templateId";
+  private static final String ANYONE_GROUP_PARAMETER = "anyoneGroup";
+
   private final MyBatis myBatis;
   private final System2 system;
 
@@ -126,30 +134,30 @@ public class PermissionTemplateDao implements Dao {
   }
 
   @CheckForNull
-  public PermissionTemplateDto selectByUuid(DbSession session, String templateKey) {
-    return mapper(session).selectByUuid(templateKey);
+  public PermissionTemplateDto selectByUuid(DbSession session, String templateUuid) {
+    return mapper(session).selectByUuid(templateUuid);
   }
 
   @CheckForNull
-  public PermissionTemplateDto selectByUuid(String templateKey) {
+  public PermissionTemplateDto selectByUuid(String templateUuid) {
     DbSession session = myBatis.openSession(false);
     try {
-      return selectByUuid(session, templateKey);
+      return selectByUuid(session, templateUuid);
     } finally {
       MyBatis.closeQuietly(session);
     }
   }
 
   @CheckForNull
-  public PermissionTemplateDto selectByUuidWithUserAndGroupPermissions(DbSession session, String templateKey) {
-    PermissionTemplateDto permissionTemplate = null;
+  public PermissionTemplateDto selectByUuidWithUserAndGroupPermissions(DbSession session, String templateUuid) {
+    PermissionTemplateDto permissionTemplate;
     PermissionTemplateMapper mapper = mapper(session);
-    permissionTemplate = mapper.selectByUuid(templateKey);
-    PermissionTemplateDto templateUsersPermissions = mapper.selectTemplateUsersPermissions(templateKey);
+    permissionTemplate = mapper.selectByUuid(templateUuid);
+    PermissionTemplateDto templateUsersPermissions = mapper.selectTemplateUsersPermissions(templateUuid);
     if (templateUsersPermissions != null) {
       permissionTemplate.setUsersPermissions(templateUsersPermissions.getUsersPermissions());
     }
-    PermissionTemplateDto templateGroupsPermissions = mapper.selectTemplateGroupsPermissions(templateKey);
+    PermissionTemplateDto templateGroupsPermissions = mapper.selectTemplateGroupsPermissions(templateUuid);
     if (templateGroupsPermissions != null) {
       permissionTemplate.setGroupsByPermission(templateGroupsPermissions.getGroupsPermissions());
     }
@@ -157,28 +165,49 @@ public class PermissionTemplateDao implements Dao {
   }
 
   @CheckForNull
-  public PermissionTemplateDto selectByUuidWithUserAndGroupPermissions(String templateKey) {
+  public PermissionTemplateDto selectByUuidWithUserAndGroupPermissions(String templateUuid) {
     DbSession session = myBatis.openSession(false);
     try {
-      return selectByUuidWithUserAndGroupPermissions(session, templateKey);
+      return selectByUuidWithUserAndGroupPermissions(session, templateUuid);
     } finally {
       MyBatis.closeQuietly(session);
     }
   }
 
-  public List<PermissionTemplateDto> selectAllPermissionTemplates(DbSession session) {
-    return session.selectList("selectAllPermissionTemplates");
+  public List<PermissionTemplateDto> selectAll(DbSession session, String nameMatch) {
+    String uppercaseNameMatch = toUppercaseSqlQuery(nameMatch);
+    return mapper(session).selectAll(uppercaseNameMatch);
+  }
+
+  public List<PermissionTemplateDto> selectAll(DbSession session) {
+    return mapper(session).selectAll(null);
   }
 
-  public List<PermissionTemplateDto> selectAllPermissionTemplates() {
+  public List<PermissionTemplateDto> selectAll() {
     DbSession session = myBatis.openSession(false);
     try {
-      return selectAllPermissionTemplates(session);
+      return selectAll(session);
     } finally {
       MyBatis.closeQuietly(session);
     }
   }
 
+  public int countAll(DbSession dbSession, String nameQuery) {
+    String upperCasedNameQuery = toUppercaseSqlQuery(nameQuery);
+
+    return mapper(dbSession).countAll(upperCasedNameQuery);
+  }
+
+  public int countAll(DbSession session) {
+    return mapper(session).countAll(null);
+  }
+
+  private static String toUppercaseSqlQuery(String nameMatch) {
+    String wildcard = "%";
+    return format("%s%s%s", wildcard, nameMatch.toUpperCase(), wildcard);
+
+  }
+
   public PermissionTemplateDto insert(DbSession session, PermissionTemplateDto permissionTemplate) {
     mapper(session).insert(permissionTemplate);
     session.commit();
@@ -186,6 +215,39 @@ public class PermissionTemplateDao implements Dao {
     return permissionTemplate;
   }
 
+  /**
+   * Each row returns a #{@link CountByProjectAndPermissionDto}
+   */
+  public void usersCountByTemplateIdAndPermission(final DbSession dbSession, List<Long> templateIds, final ResultHandler resultHandler) {
+    final Map<String, Object> parameters = new HashMap<>();
+
+    executeLargeInputsWithoutOutput(templateIds, new Function<List<Long>, Void>() {
+      @Override
+      public Void apply(@Nonnull List<Long> partitionedTemplateIds) {
+        parameters.put("templateIds", partitionedTemplateIds);
+        mapper(dbSession).usersCountByTemplateIdAndPermission(parameters, resultHandler);
+        return null;
+      }
+    });
+  }
+
+  /**
+   * Each row returns a #{@link CountByProjectAndPermissionDto}
+   */
+  public void groupsCountByTemplateIdAndPermission(final DbSession dbSession, final List<Long> templateIds, final ResultHandler resultHandler) {
+    final Map<String, Object> parameters = new HashMap<>();
+    parameters.put(ANYONE_GROUP_PARAMETER, DefaultGroups.ANYONE);
+
+    executeLargeInputsWithoutOutput(templateIds, new Function<List<Long>, Void>() {
+      @Override
+      public Void apply(@Nonnull List<Long> partitionedTemplateIds) {
+        parameters.put("templateIds", partitionedTemplateIds);
+        mapper(dbSession).groupsCountByTemplateIdAndPermission(parameters, resultHandler);
+        return null;
+      }
+    });
+  }
+
   public void deleteById(DbSession session, long templateId) {
     PermissionTemplateMapper mapper = mapper(session);
     mapper.deleteUserPermissions(templateId);
@@ -267,6 +329,10 @@ public class PermissionTemplateDao implements Dao {
     session.commit();
   }
 
+  /**
+   * @deprecated since 5.2 use {@link #insertGroupPermission(DbSession, Long, Long, String)}
+   */
+  @Deprecated
   public void insertGroupPermission(Long templateId, @Nullable Long groupId, String permission) {
     DbSession session = myBatis.openSession(false);
     try {
@@ -309,26 +375,18 @@ public class PermissionTemplateDao implements Dao {
     session.commit();
   }
 
-  public void deleteGroupPermissions(DbSession session, long templateId) {
-    mapper(session).deleteGroupPermissions(templateId);
-  }
-
-  public void deleteUserPermissions(DbSession session, long templateId) {
-    mapper(session).deleteUserPermissions(templateId);
-  }
-
   /**
    * Load permission template and load associated collections of users and groups permissions
    */
   @VisibleForTesting
-  PermissionTemplateDto selectPermissionTemplateWithPermissions(DbSession session, String templateKey) {
-    PermissionTemplateDto permissionTemplateDto = selectByUuid(session, templateKey);
+  PermissionTemplateDto selectPermissionTemplateWithPermissions(DbSession session, String templateUuid) {
+    PermissionTemplateDto permissionTemplateDto = selectByUuid(session, templateUuid);
     if (permissionTemplateDto == null) {
-      throw new IllegalArgumentException("Could not retrieve permission template with key " + templateKey);
+      throw new IllegalArgumentException("Could not retrieve permission template with uuid " + templateUuid);
     }
     PermissionTemplateDto templateWithPermissions = selectByUuidWithUserAndGroupPermissions(session, permissionTemplateDto.getKee());
     if (templateWithPermissions == null) {
-      throw new IllegalArgumentException("Could not retrieve permissions for template with key " + templateKey);
+      throw new IllegalArgumentException("Could not retrieve permissions for template with uuid " + templateUuid);
     }
     return templateWithPermissions;
   }
index d4006be65e9ed7aaadde3b3340bee9566342e76a..93f5ef797773477775b25451c0dff5ca9d5c3702 100644 (file)
@@ -22,6 +22,8 @@ package org.sonar.db.permission;
 
 import java.util.List;
 import java.util.Map;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.session.ResultHandler;
 import org.apache.ibatis.session.RowBounds;
 
 /**
@@ -64,4 +66,12 @@ public interface PermissionTemplateMapper {
   int countUsers(Map<String, Object> params);
 
   int countGroups(Map<String, Object> parameters);
+
+  List<PermissionTemplateDto> selectAll(@Param("nameMatch") String nameMatch);
+
+  int countAll(@Param("nameMatch") String nameMatch);
+
+  void usersCountByTemplateIdAndPermission(Map<String, Object> parameters, ResultHandler resultHandler);
+
+  void groupsCountByTemplateIdAndPermission(Map<String, Object> parameters, ResultHandler resultHandler);
 }
index 7381e9e761650b3fb0607007b09437a821adfe5b..a1bc0c2ccb5645528dbc2d07cdaecebacf8cad4e 100644 (file)
     WHERE kee=#{uuid}
   </select>
 
-  <select id="selectAllPermissionTemplates" resultType="PermissionTemplate">
+  <select id="selectAll" parameterType="map" resultType="PermissionTemplate">
     SELECT
     <include refid="templateColumns"/>
     FROM permission_templates
+    <where>
+      <if test="nameMatch!=null">
+        AND (UPPER(name) LIKE #{nameMatch} ESCAPE '/')
+      </if>
+    </where>
+    ORDER BY UPPER(name), name
+  </select>
+
+  <select id="countAll" parameterType="String" resultType="int">
+    SELECT count(id)
+    FROM permission_templates
+    <where>
+      <if test="nameMatch!=null">
+        AND (UPPER(name) LIKE #{nameMatch} ESCAPE '/')
+      </if>
+    </where>
   </select>
 
   <select id="selectByName" parameterType="String" resultType="PermissionTemplate">
     AND (g.name IS NOT NULL OR ptg.group_id IS NULL)
   </select>
 
+  <select id="usersCountByTemplateIdAndPermission" parameterType="map"
+          resultType="org.sonar.db.permission.CountByTemplateAndPermissionDto">
+    SELECT ptu.template_id as templateId, ptu.permission_reference as permission, count(u.login) as count
+    FROM users u
+    INNER JOIN perm_templates_users ptu ON ptu.user_id=u.id
+    AND ptu.template_id in
+    <foreach collection="templateIds" open="(" close=")" item="id" separator=",">
+      #{id}
+    </foreach>
+    <where>
+      AND u.active = ${_true}
+    </where>
+    GROUP BY ptu.template_id, ptu.permission_reference
+  </select>
+
+  <select id="groupsCountByTemplateIdAndPermission" parameterType="map"
+          resultType="org.sonar.db.permission.CountByTemplateAndPermissionDto">
+    SELECT count(name) as count, permission, templateId
+    FROM
+    (SELECT g.name as name, ptg.permission_reference as permission, ptg.template_id as templateId
+    FROM groups g
+    INNER JOIN perm_templates_groups ptg ON ptg.group_id=g.id
+    UNION
+    -- Add Anyone group permission
+    SELECT #{anyoneGroup} as name, ptg.permission_reference as permission, ptg.template_id as templateId
+    FROM perm_templates_groups ptg
+    <where>
+      AND ptg.group_id IS NULL
+    </where>
+    ) groups
+    <where>
+      AND groups.templateId in
+      <foreach collection="templateIds" open="(" close=")" item="id" separator=",">
+        #{id}
+      </foreach>
+    </where>
+    GROUP BY groups.permission, groups.templateId
+  </select>
+
   <resultMap id="fullPermissionsTemplateResult" type="PermissionTemplate">
     <id property="id" column="template_id"/>
     <result property="name" column="template_name"/>
index b75c082da79f7fb7a235d069a6d6e7bd21fd7f86..be7ccfcc78b96270d308f3848668c3eb319ceac2 100644 (file)
@@ -22,23 +22,37 @@ package org.sonar.db.permission;
 
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
+import javax.annotation.Nullable;
+import org.apache.ibatis.session.ResultContext;
+import org.apache.ibatis.session.ResultHandler;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.utils.System2;
+import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.MyBatis;
+import org.sonar.db.user.GroupDto;
+import org.sonar.db.user.UserDto;
 import org.sonar.test.DbTests;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.sonar.api.web.UserRole.ADMIN;
+import static org.sonar.api.web.UserRole.CODEVIEWER;
+import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
+import static org.sonar.api.web.UserRole.USER;
 import static org.sonar.db.permission.PermissionTemplateTesting.newPermissionTemplateDto;
+import static org.sonar.db.user.GroupTesting.newGroupDto;
+import static org.sonar.db.user.UserTesting.newUserDto;
 
 @Category(DbTests.class)
 public class PermissionTemplateDaoTest {
@@ -51,6 +65,7 @@ public class PermissionTemplateDaoTest {
   public ExpectedException expectedException = ExpectedException.none();
 
   DbSession session = db.getSession();
+  DbClient dbClient = db.getDbClient();
 
   PermissionTemplateDao underTest = new PermissionTemplateDao(db.myBatis(), system);
 
@@ -142,8 +157,9 @@ public class PermissionTemplateDaoTest {
   @Test
   public void should_select_all_permission_templates() {
     db.prepareDbUnit(getClass(), "selectAllPermissionTemplates.xml");
+    commit();
 
-    List<PermissionTemplateDto> permissionTemplates = underTest.selectAllPermissionTemplates();
+    List<PermissionTemplateDto> permissionTemplates = underTest.selectAll();
 
     assertThat(permissionTemplates).hasSize(3);
     assertThat(permissionTemplates).extracting("id").containsOnly(1L, 2L, 3L);
@@ -260,6 +276,110 @@ public class PermissionTemplateDaoTest {
     underTest.selectPermissionTemplateWithPermissions(db.getSession(), "unmatched");
   }
 
+  @Test
+  public void group_count_by_template_and_permission() {
+    PermissionTemplateDto template1 = insertTemplate(newPermissionTemplateDto());
+    PermissionTemplateDto template2 = insertTemplate(newPermissionTemplateDto());
+    PermissionTemplateDto template3 = insertTemplate(newPermissionTemplateDto());
+
+    GroupDto group1 = insertGroup(newGroupDto());
+    GroupDto group2 = insertGroup(newGroupDto());
+    GroupDto group3 = insertGroup(newGroupDto());
+
+    addGroupToTemplate(42L, group1.getId(), ISSUE_ADMIN);
+    addGroupToTemplate(template1.getId(), group1.getId(), CODEVIEWER);
+    addGroupToTemplate(template1.getId(), group2.getId(), CODEVIEWER);
+    addGroupToTemplate(template1.getId(), group3.getId(), CODEVIEWER);
+    addGroupToTemplate(template1.getId(), null, CODEVIEWER);
+    addGroupToTemplate(template1.getId(), group1.getId(), ADMIN);
+    addGroupToTemplate(template2.getId(), group1.getId(), ADMIN);
+
+    commit();
+
+    final List<CountByTemplateAndPermissionDto> result = new ArrayList<>();
+    underTest.groupsCountByTemplateIdAndPermission(session, Arrays.asList(template1.getId(), template2.getId(), template3.getId()), new ResultHandler() {
+      @Override
+      public void handleResult(ResultContext context) {
+        result.add((CountByTemplateAndPermissionDto) context.getResultObject());
+      }
+    });
+
+    assertThat(result).hasSize(3);
+    assertThat(result).extracting("permission").containsOnly(ADMIN, CODEVIEWER);
+    assertThat(result).extracting("templateId").containsOnly(template1.getId(), template2.getId());
+    assertThat(result).extracting("count").containsOnly(4, 1);
+  }
+
+  @Test
+  public void user_count_by_template_and_permission() {
+    PermissionTemplateDto template1 = insertTemplate(newPermissionTemplateDto());
+    PermissionTemplateDto template2 = insertTemplate(newPermissionTemplateDto());
+    PermissionTemplateDto template3 = insertTemplate(newPermissionTemplateDto());
+
+    UserDto user1 = insertUser(newUserDto());
+    UserDto user2 = insertUser(newUserDto());
+    UserDto user3 = insertUser(newUserDto());
+
+    addUserToTemplate(42L, user1.getId(), ISSUE_ADMIN);
+    addUserToTemplate(template1.getId(), user1.getId(), ADMIN);
+    addUserToTemplate(template1.getId(), user2.getId(), ADMIN);
+    addUserToTemplate(template1.getId(), user3.getId(), ADMIN);
+    addUserToTemplate(template1.getId(), user1.getId(), USER);
+    addUserToTemplate(template2.getId(), user1.getId(), USER);
+
+    commit();
+
+    final List<CountByTemplateAndPermissionDto> result = new ArrayList<>();
+    underTest.usersCountByTemplateIdAndPermission(session, Arrays.asList(template1.getId(), template2.getId(), template3.getId()), new ResultHandler() {
+      @Override
+      public void handleResult(ResultContext context) {
+        result.add((CountByTemplateAndPermissionDto) context.getResultObject());
+      }
+    });
+    assertThat(result).hasSize(3);
+    assertThat(result).extracting("permission").containsOnly(ADMIN, USER);
+    assertThat(result).extracting("templateId").containsOnly(template1.getId(), template2.getId());
+    assertThat(result).extracting("count").containsOnly(3, 1);
+
+  }
+
+  @Test
+  public void select_by_name_query_and_pagination() {
+    insertTemplate(newPermissionTemplateDto().setName("aaabbb"));
+    insertTemplate(newPermissionTemplateDto().setName("aaaccc"));
+    commit();
+
+    List<PermissionTemplateDto> templates = underTest.selectAll(session, "aaa");
+    int count = underTest.countAll(session, "aaa");
+
+    assertThat(templates.get(0).getName()).isEqualTo("aaabbb");
+    assertThat(count).isEqualTo(2);
+  }
+
+  private PermissionTemplateDto insertTemplate(PermissionTemplateDto template) {
+    return dbClient.permissionTemplateDao().insert(session, template);
+  }
+
+  private GroupDto insertGroup(GroupDto groupDto) {
+    return dbClient.groupDao().insert(session, groupDto);
+  }
+
+  private UserDto insertUser(UserDto userDto) {
+    return dbClient.userDao().insert(session, userDto.setActive(true));
+  }
+
+  private void addGroupToTemplate(long templateId, @Nullable Long groupId, String permission) {
+    dbClient.permissionTemplateDao().insertGroupPermission(session, templateId, groupId, permission);
+  }
+
+  private void addUserToTemplate(long templateId, long userId, String permission) {
+    dbClient.permissionTemplateDao().insertUserPermission(session, templateId, userId, permission);
+  }
+
+  private void commit() {
+    session.commit();
+  }
+
   private void checkTemplateTables(String fileName) {
     db.assertDbUnitTable(getClass(), fileName, "permission_templates", "id", "name", "description");
     db.assertDbUnitTable(getClass(), fileName, "perm_templates_users", "id", "template_id", "user_id", "permission_reference");
index 49a027f7c9c3109e107a3f1c02d492644d1d1bb8..34af0db82e850c1b52556cd57a46e31bd6ed676c 100644 (file)
@@ -7764,6 +7764,39 @@ public final class Permissions {
      */
     com.google.protobuf.ByteString
         getUpdatedAtBytes();
+
+    /**
+     * <code>optional bool permissionsPresentIfEmpty = 7;</code>
+     */
+    boolean hasPermissionsPresentIfEmpty();
+    /**
+     * <code>optional bool permissionsPresentIfEmpty = 7;</code>
+     */
+    boolean getPermissionsPresentIfEmpty();
+
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+     */
+    java.util.List<org.sonarqube.ws.Permissions.Permission> 
+        getPermissionsList();
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+     */
+    org.sonarqube.ws.Permissions.Permission getPermissions(int index);
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+     */
+    int getPermissionsCount();
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+     */
+    java.util.List<? extends org.sonarqube.ws.Permissions.PermissionOrBuilder> 
+        getPermissionsOrBuilderList();
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+     */
+    org.sonarqube.ws.Permissions.PermissionOrBuilder getPermissionsOrBuilder(
+        int index);
   }
   /**
    * Protobuf type {@code sonarqube.ws.permissions.PermissionTemplate}
@@ -7853,6 +7886,19 @@ public final class Permissions {
               updatedAt_ = bs;
               break;
             }
+            case 56: {
+              bitField0_ |= 0x00000040;
+              permissionsPresentIfEmpty_ = input.readBool();
+              break;
+            }
+            case 66: {
+              if (!((mutable_bitField0_ & 0x00000080) == 0x00000080)) {
+                permissions_ = new java.util.ArrayList<org.sonarqube.ws.Permissions.Permission>();
+                mutable_bitField0_ |= 0x00000080;
+              }
+              permissions_.add(input.readMessage(org.sonarqube.ws.Permissions.Permission.PARSER, extensionRegistry));
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -7861,6 +7907,9 @@ public final class Permissions {
         throw new com.google.protobuf.InvalidProtocolBufferException(
             e.getMessage()).setUnfinishedMessage(this);
       } finally {
+        if (((mutable_bitField0_ & 0x00000080) == 0x00000080)) {
+          permissions_ = java.util.Collections.unmodifiableList(permissions_);
+        }
         this.unknownFields = unknownFields.build();
         makeExtensionsImmutable();
       }
@@ -8169,6 +8218,56 @@ public final class Permissions {
       }
     }
 
+    public static final int PERMISSIONSPRESENTIFEMPTY_FIELD_NUMBER = 7;
+    private boolean permissionsPresentIfEmpty_;
+    /**
+     * <code>optional bool permissionsPresentIfEmpty = 7;</code>
+     */
+    public boolean hasPermissionsPresentIfEmpty() {
+      return ((bitField0_ & 0x00000040) == 0x00000040);
+    }
+    /**
+     * <code>optional bool permissionsPresentIfEmpty = 7;</code>
+     */
+    public boolean getPermissionsPresentIfEmpty() {
+      return permissionsPresentIfEmpty_;
+    }
+
+    public static final int PERMISSIONS_FIELD_NUMBER = 8;
+    private java.util.List<org.sonarqube.ws.Permissions.Permission> permissions_;
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+     */
+    public java.util.List<org.sonarqube.ws.Permissions.Permission> getPermissionsList() {
+      return permissions_;
+    }
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+     */
+    public java.util.List<? extends org.sonarqube.ws.Permissions.PermissionOrBuilder> 
+        getPermissionsOrBuilderList() {
+      return permissions_;
+    }
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+     */
+    public int getPermissionsCount() {
+      return permissions_.size();
+    }
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+     */
+    public org.sonarqube.ws.Permissions.Permission getPermissions(int index) {
+      return permissions_.get(index);
+    }
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+     */
+    public org.sonarqube.ws.Permissions.PermissionOrBuilder getPermissionsOrBuilder(
+        int index) {
+      return permissions_.get(index);
+    }
+
     private void initFields() {
       id_ = "";
       name_ = "";
@@ -8176,6 +8275,8 @@ public final class Permissions {
       projectKeyPattern_ = "";
       createdAt_ = "";
       updatedAt_ = "";
+      permissionsPresentIfEmpty_ = false;
+      permissions_ = java.util.Collections.emptyList();
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -8208,6 +8309,12 @@ public final class Permissions {
       if (((bitField0_ & 0x00000020) == 0x00000020)) {
         output.writeBytes(6, getUpdatedAtBytes());
       }
+      if (((bitField0_ & 0x00000040) == 0x00000040)) {
+        output.writeBool(7, permissionsPresentIfEmpty_);
+      }
+      for (int i = 0; i < permissions_.size(); i++) {
+        output.writeMessage(8, permissions_.get(i));
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -8241,6 +8348,14 @@ public final class Permissions {
         size += com.google.protobuf.CodedOutputStream
           .computeBytesSize(6, getUpdatedAtBytes());
       }
+      if (((bitField0_ & 0x00000040) == 0x00000040)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBoolSize(7, permissionsPresentIfEmpty_);
+      }
+      for (int i = 0; i < permissions_.size(); i++) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(8, permissions_.get(i));
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -8350,6 +8465,7 @@ public final class Permissions {
       }
       private void maybeForceBuilderInitialization() {
         if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+          getPermissionsFieldBuilder();
         }
       }
       private static Builder create() {
@@ -8370,6 +8486,14 @@ public final class Permissions {
         bitField0_ = (bitField0_ & ~0x00000010);
         updatedAt_ = "";
         bitField0_ = (bitField0_ & ~0x00000020);
+        permissionsPresentIfEmpty_ = false;
+        bitField0_ = (bitField0_ & ~0x00000040);
+        if (permissionsBuilder_ == null) {
+          permissions_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000080);
+        } else {
+          permissionsBuilder_.clear();
+        }
         return this;
       }
 
@@ -8422,6 +8546,19 @@ public final class Permissions {
           to_bitField0_ |= 0x00000020;
         }
         result.updatedAt_ = updatedAt_;
+        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {
+          to_bitField0_ |= 0x00000040;
+        }
+        result.permissionsPresentIfEmpty_ = permissionsPresentIfEmpty_;
+        if (permissionsBuilder_ == null) {
+          if (((bitField0_ & 0x00000080) == 0x00000080)) {
+            permissions_ = java.util.Collections.unmodifiableList(permissions_);
+            bitField0_ = (bitField0_ & ~0x00000080);
+          }
+          result.permissions_ = permissions_;
+        } else {
+          result.permissions_ = permissionsBuilder_.build();
+        }
         result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
@@ -8468,6 +8605,35 @@ public final class Permissions {
           updatedAt_ = other.updatedAt_;
           onChanged();
         }
+        if (other.hasPermissionsPresentIfEmpty()) {
+          setPermissionsPresentIfEmpty(other.getPermissionsPresentIfEmpty());
+        }
+        if (permissionsBuilder_ == null) {
+          if (!other.permissions_.isEmpty()) {
+            if (permissions_.isEmpty()) {
+              permissions_ = other.permissions_;
+              bitField0_ = (bitField0_ & ~0x00000080);
+            } else {
+              ensurePermissionsIsMutable();
+              permissions_.addAll(other.permissions_);
+            }
+            onChanged();
+          }
+        } else {
+          if (!other.permissions_.isEmpty()) {
+            if (permissionsBuilder_.isEmpty()) {
+              permissionsBuilder_.dispose();
+              permissionsBuilder_ = null;
+              permissions_ = other.permissions_;
+              bitField0_ = (bitField0_ & ~0x00000080);
+              permissionsBuilder_ = 
+                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
+                   getPermissionsFieldBuilder() : null;
+            } else {
+              permissionsBuilder_.addAllMessages(other.permissions_);
+            }
+          }
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -8999,135 +9165,915 @@ public final class Permissions {
         return this;
       }
 
-      // @@protoc_insertion_point(builder_scope:sonarqube.ws.permissions.PermissionTemplate)
-    }
-
-    static {
-      defaultInstance = new PermissionTemplate(true);
-      defaultInstance.initFields();
-    }
-
-    // @@protoc_insertion_point(class_scope:sonarqube.ws.permissions.PermissionTemplate)
-  }
-
-  public interface CreatePermissionTemplateResponseOrBuilder extends
-      // @@protoc_insertion_point(interface_extends:sonarqube.ws.permissions.CreatePermissionTemplateResponse)
-      com.google.protobuf.MessageOrBuilder {
-
-    /**
-     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
-     */
-    boolean hasPermissionTemplate();
-    /**
-     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
-     */
-    org.sonarqube.ws.Permissions.PermissionTemplate getPermissionTemplate();
-    /**
-     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
-     */
-    org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder getPermissionTemplateOrBuilder();
-  }
-  /**
-   * Protobuf type {@code sonarqube.ws.permissions.CreatePermissionTemplateResponse}
-   */
-  public static final class CreatePermissionTemplateResponse extends
-      com.google.protobuf.GeneratedMessage implements
-      // @@protoc_insertion_point(message_implements:sonarqube.ws.permissions.CreatePermissionTemplateResponse)
-      CreatePermissionTemplateResponseOrBuilder {
-    // Use CreatePermissionTemplateResponse.newBuilder() to construct.
-    private CreatePermissionTemplateResponse(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
-      super(builder);
-      this.unknownFields = builder.getUnknownFields();
-    }
-    private CreatePermissionTemplateResponse(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
+      private boolean permissionsPresentIfEmpty_ ;
+      /**
+       * <code>optional bool permissionsPresentIfEmpty = 7;</code>
+       */
+      public boolean hasPermissionsPresentIfEmpty() {
+        return ((bitField0_ & 0x00000040) == 0x00000040);
+      }
+      /**
+       * <code>optional bool permissionsPresentIfEmpty = 7;</code>
+       */
+      public boolean getPermissionsPresentIfEmpty() {
+        return permissionsPresentIfEmpty_;
+      }
+      /**
+       * <code>optional bool permissionsPresentIfEmpty = 7;</code>
+       */
+      public Builder setPermissionsPresentIfEmpty(boolean value) {
+        bitField0_ |= 0x00000040;
+        permissionsPresentIfEmpty_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional bool permissionsPresentIfEmpty = 7;</code>
+       */
+      public Builder clearPermissionsPresentIfEmpty() {
+        bitField0_ = (bitField0_ & ~0x00000040);
+        permissionsPresentIfEmpty_ = false;
+        onChanged();
+        return this;
+      }
 
-    private static final CreatePermissionTemplateResponse defaultInstance;
-    public static CreatePermissionTemplateResponse getDefaultInstance() {
-      return defaultInstance;
-    }
+      private java.util.List<org.sonarqube.ws.Permissions.Permission> permissions_ =
+        java.util.Collections.emptyList();
+      private void ensurePermissionsIsMutable() {
+        if (!((bitField0_ & 0x00000080) == 0x00000080)) {
+          permissions_ = new java.util.ArrayList<org.sonarqube.ws.Permissions.Permission>(permissions_);
+          bitField0_ |= 0x00000080;
+         }
+      }
 
-    public CreatePermissionTemplateResponse getDefaultInstanceForType() {
-      return defaultInstance;
-    }
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonarqube.ws.Permissions.Permission, org.sonarqube.ws.Permissions.Permission.Builder, org.sonarqube.ws.Permissions.PermissionOrBuilder> permissionsBuilder_;
 
-    private final com.google.protobuf.UnknownFieldSet unknownFields;
-    @java.lang.Override
-    public final com.google.protobuf.UnknownFieldSet
-        getUnknownFields() {
-      return this.unknownFields;
-    }
-    private CreatePermissionTemplateResponse(
-        com.google.protobuf.CodedInputStream input,
-        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-        throws com.google.protobuf.InvalidProtocolBufferException {
-      initFields();
-      int mutable_bitField0_ = 0;
-      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
-          com.google.protobuf.UnknownFieldSet.newBuilder();
-      try {
-        boolean done = false;
-        while (!done) {
-          int tag = input.readTag();
-          switch (tag) {
-            case 0:
-              done = true;
-              break;
-            default: {
-              if (!parseUnknownField(input, unknownFields,
-                                     extensionRegistry, tag)) {
-                done = true;
-              }
-              break;
-            }
-            case 10: {
-              org.sonarqube.ws.Permissions.PermissionTemplate.Builder subBuilder = null;
-              if (((bitField0_ & 0x00000001) == 0x00000001)) {
-                subBuilder = permissionTemplate_.toBuilder();
-              }
-              permissionTemplate_ = input.readMessage(org.sonarqube.ws.Permissions.PermissionTemplate.PARSER, extensionRegistry);
-              if (subBuilder != null) {
-                subBuilder.mergeFrom(permissionTemplate_);
-                permissionTemplate_ = subBuilder.buildPartial();
-              }
-              bitField0_ |= 0x00000001;
-              break;
-            }
-          }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public java.util.List<org.sonarqube.ws.Permissions.Permission> getPermissionsList() {
+        if (permissionsBuilder_ == null) {
+          return java.util.Collections.unmodifiableList(permissions_);
+        } else {
+          return permissionsBuilder_.getMessageList();
         }
-      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
-        throw e.setUnfinishedMessage(this);
-      } catch (java.io.IOException e) {
-        throw new com.google.protobuf.InvalidProtocolBufferException(
-            e.getMessage()).setUnfinishedMessage(this);
-      } finally {
-        this.unknownFields = unknownFields.build();
-        makeExtensionsImmutable();
       }
-    }
-    public static final com.google.protobuf.Descriptors.Descriptor
-        getDescriptor() {
-      return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_CreatePermissionTemplateResponse_descriptor;
-    }
-
-    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
-        internalGetFieldAccessorTable() {
-      return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_CreatePermissionTemplateResponse_fieldAccessorTable
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public int getPermissionsCount() {
+        if (permissionsBuilder_ == null) {
+          return permissions_.size();
+        } else {
+          return permissionsBuilder_.getCount();
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public org.sonarqube.ws.Permissions.Permission getPermissions(int index) {
+        if (permissionsBuilder_ == null) {
+          return permissions_.get(index);
+        } else {
+          return permissionsBuilder_.getMessage(index);
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public Builder setPermissions(
+          int index, org.sonarqube.ws.Permissions.Permission value) {
+        if (permissionsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensurePermissionsIsMutable();
+          permissions_.set(index, value);
+          onChanged();
+        } else {
+          permissionsBuilder_.setMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public Builder setPermissions(
+          int index, org.sonarqube.ws.Permissions.Permission.Builder builderForValue) {
+        if (permissionsBuilder_ == null) {
+          ensurePermissionsIsMutable();
+          permissions_.set(index, builderForValue.build());
+          onChanged();
+        } else {
+          permissionsBuilder_.setMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public Builder addPermissions(org.sonarqube.ws.Permissions.Permission value) {
+        if (permissionsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensurePermissionsIsMutable();
+          permissions_.add(value);
+          onChanged();
+        } else {
+          permissionsBuilder_.addMessage(value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public Builder addPermissions(
+          int index, org.sonarqube.ws.Permissions.Permission value) {
+        if (permissionsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensurePermissionsIsMutable();
+          permissions_.add(index, value);
+          onChanged();
+        } else {
+          permissionsBuilder_.addMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public Builder addPermissions(
+          org.sonarqube.ws.Permissions.Permission.Builder builderForValue) {
+        if (permissionsBuilder_ == null) {
+          ensurePermissionsIsMutable();
+          permissions_.add(builderForValue.build());
+          onChanged();
+        } else {
+          permissionsBuilder_.addMessage(builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public Builder addPermissions(
+          int index, org.sonarqube.ws.Permissions.Permission.Builder builderForValue) {
+        if (permissionsBuilder_ == null) {
+          ensurePermissionsIsMutable();
+          permissions_.add(index, builderForValue.build());
+          onChanged();
+        } else {
+          permissionsBuilder_.addMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public Builder addAllPermissions(
+          java.lang.Iterable<? extends org.sonarqube.ws.Permissions.Permission> values) {
+        if (permissionsBuilder_ == null) {
+          ensurePermissionsIsMutable();
+          com.google.protobuf.AbstractMessageLite.Builder.addAll(
+              values, permissions_);
+          onChanged();
+        } else {
+          permissionsBuilder_.addAllMessages(values);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public Builder clearPermissions() {
+        if (permissionsBuilder_ == null) {
+          permissions_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000080);
+          onChanged();
+        } else {
+          permissionsBuilder_.clear();
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public Builder removePermissions(int index) {
+        if (permissionsBuilder_ == null) {
+          ensurePermissionsIsMutable();
+          permissions_.remove(index);
+          onChanged();
+        } else {
+          permissionsBuilder_.remove(index);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public org.sonarqube.ws.Permissions.Permission.Builder getPermissionsBuilder(
+          int index) {
+        return getPermissionsFieldBuilder().getBuilder(index);
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public org.sonarqube.ws.Permissions.PermissionOrBuilder getPermissionsOrBuilder(
+          int index) {
+        if (permissionsBuilder_ == null) {
+          return permissions_.get(index);  } else {
+          return permissionsBuilder_.getMessageOrBuilder(index);
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public java.util.List<? extends org.sonarqube.ws.Permissions.PermissionOrBuilder> 
+           getPermissionsOrBuilderList() {
+        if (permissionsBuilder_ != null) {
+          return permissionsBuilder_.getMessageOrBuilderList();
+        } else {
+          return java.util.Collections.unmodifiableList(permissions_);
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public org.sonarqube.ws.Permissions.Permission.Builder addPermissionsBuilder() {
+        return getPermissionsFieldBuilder().addBuilder(
+            org.sonarqube.ws.Permissions.Permission.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public org.sonarqube.ws.Permissions.Permission.Builder addPermissionsBuilder(
+          int index) {
+        return getPermissionsFieldBuilder().addBuilder(
+            index, org.sonarqube.ws.Permissions.Permission.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 8;</code>
+       */
+      public java.util.List<org.sonarqube.ws.Permissions.Permission.Builder> 
+           getPermissionsBuilderList() {
+        return getPermissionsFieldBuilder().getBuilderList();
+      }
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonarqube.ws.Permissions.Permission, org.sonarqube.ws.Permissions.Permission.Builder, org.sonarqube.ws.Permissions.PermissionOrBuilder> 
+          getPermissionsFieldBuilder() {
+        if (permissionsBuilder_ == null) {
+          permissionsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
+              org.sonarqube.ws.Permissions.Permission, org.sonarqube.ws.Permissions.Permission.Builder, org.sonarqube.ws.Permissions.PermissionOrBuilder>(
+                  permissions_,
+                  ((bitField0_ & 0x00000080) == 0x00000080),
+                  getParentForChildren(),
+                  isClean());
+          permissions_ = null;
+        }
+        return permissionsBuilder_;
+      }
+
+      // @@protoc_insertion_point(builder_scope:sonarqube.ws.permissions.PermissionTemplate)
+    }
+
+    static {
+      defaultInstance = new PermissionTemplate(true);
+      defaultInstance.initFields();
+    }
+
+    // @@protoc_insertion_point(class_scope:sonarqube.ws.permissions.PermissionTemplate)
+  }
+
+  public interface CreatePermissionTemplateResponseOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:sonarqube.ws.permissions.CreatePermissionTemplateResponse)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+     */
+    boolean hasPermissionTemplate();
+    /**
+     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+     */
+    org.sonarqube.ws.Permissions.PermissionTemplate getPermissionTemplate();
+    /**
+     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+     */
+    org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder getPermissionTemplateOrBuilder();
+  }
+  /**
+   * Protobuf type {@code sonarqube.ws.permissions.CreatePermissionTemplateResponse}
+   */
+  public static final class CreatePermissionTemplateResponse extends
+      com.google.protobuf.GeneratedMessage implements
+      // @@protoc_insertion_point(message_implements:sonarqube.ws.permissions.CreatePermissionTemplateResponse)
+      CreatePermissionTemplateResponseOrBuilder {
+    // Use CreatePermissionTemplateResponse.newBuilder() to construct.
+    private CreatePermissionTemplateResponse(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
+      super(builder);
+      this.unknownFields = builder.getUnknownFields();
+    }
+    private CreatePermissionTemplateResponse(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
+
+    private static final CreatePermissionTemplateResponse defaultInstance;
+    public static CreatePermissionTemplateResponse getDefaultInstance() {
+      return defaultInstance;
+    }
+
+    public CreatePermissionTemplateResponse getDefaultInstanceForType() {
+      return defaultInstance;
+    }
+
+    private final com.google.protobuf.UnknownFieldSet unknownFields;
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+        getUnknownFields() {
+      return this.unknownFields;
+    }
+    private CreatePermissionTemplateResponse(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      initFields();
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            default: {
+              if (!parseUnknownField(input, unknownFields,
+                                     extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+            case 10: {
+              org.sonarqube.ws.Permissions.PermissionTemplate.Builder subBuilder = null;
+              if (((bitField0_ & 0x00000001) == 0x00000001)) {
+                subBuilder = permissionTemplate_.toBuilder();
+              }
+              permissionTemplate_ = input.readMessage(org.sonarqube.ws.Permissions.PermissionTemplate.PARSER, extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(permissionTemplate_);
+                permissionTemplate_ = subBuilder.buildPartial();
+              }
+              bitField0_ |= 0x00000001;
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(this);
+      } catch (java.io.IOException e) {
+        throw new com.google.protobuf.InvalidProtocolBufferException(
+            e.getMessage()).setUnfinishedMessage(this);
+      } finally {
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_CreatePermissionTemplateResponse_descriptor;
+    }
+
+    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_CreatePermissionTemplateResponse_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse.class, org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse.Builder.class);
+    }
+
+    public static com.google.protobuf.Parser<CreatePermissionTemplateResponse> PARSER =
+        new com.google.protobuf.AbstractParser<CreatePermissionTemplateResponse>() {
+      public CreatePermissionTemplateResponse parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        return new CreatePermissionTemplateResponse(input, extensionRegistry);
+      }
+    };
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<CreatePermissionTemplateResponse> getParserForType() {
+      return PARSER;
+    }
+
+    private int bitField0_;
+    public static final int PERMISSIONTEMPLATE_FIELD_NUMBER = 1;
+    private org.sonarqube.ws.Permissions.PermissionTemplate permissionTemplate_;
+    /**
+     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+     */
+    public boolean hasPermissionTemplate() {
+      return ((bitField0_ & 0x00000001) == 0x00000001);
+    }
+    /**
+     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+     */
+    public org.sonarqube.ws.Permissions.PermissionTemplate getPermissionTemplate() {
+      return permissionTemplate_;
+    }
+    /**
+     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+     */
+    public org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder getPermissionTemplateOrBuilder() {
+      return permissionTemplate_;
+    }
+
+    private void initFields() {
+      permissionTemplate_ = org.sonarqube.ws.Permissions.PermissionTemplate.getDefaultInstance();
+    }
+    private byte memoizedIsInitialized = -1;
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized == 1) return true;
+      if (isInitialized == 0) return false;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      getSerializedSize();
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        output.writeMessage(1, permissionTemplate_);
+      }
+      getUnknownFields().writeTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public int getSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(1, permissionTemplate_);
+      }
+      size += getUnknownFields().getSerializedSize();
+      memoizedSerializedSize = size;
+      return size;
+    }
+
+    private static final long serialVersionUID = 0L;
+    @java.lang.Override
+    protected java.lang.Object writeReplace()
+        throws java.io.ObjectStreamException {
+      return super.writeReplace();
+    }
+
+    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input);
+    }
+    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input, extensionRegistry);
+    }
+    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+
+    public static Builder newBuilder() { return Builder.create(); }
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder(org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse prototype) {
+      return newBuilder().mergeFrom(prototype);
+    }
+    public Builder toBuilder() { return newBuilder(this); }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code sonarqube.ws.permissions.CreatePermissionTemplateResponse}
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessage.Builder<Builder> implements
+        // @@protoc_insertion_point(builder_implements:sonarqube.ws.permissions.CreatePermissionTemplateResponse)
+        org.sonarqube.ws.Permissions.CreatePermissionTemplateResponseOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_CreatePermissionTemplateResponse_descriptor;
+      }
+
+      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_CreatePermissionTemplateResponse_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse.class, org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse.Builder.class);
+      }
+
+      // Construct using org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+          getPermissionTemplateFieldBuilder();
+        }
+      }
+      private static Builder create() {
+        return new Builder();
+      }
+
+      public Builder clear() {
+        super.clear();
+        if (permissionTemplateBuilder_ == null) {
+          permissionTemplate_ = org.sonarqube.ws.Permissions.PermissionTemplate.getDefaultInstance();
+        } else {
+          permissionTemplateBuilder_.clear();
+        }
+        bitField0_ = (bitField0_ & ~0x00000001);
+        return this;
+      }
+
+      public Builder clone() {
+        return create().mergeFrom(buildPartial());
+      }
+
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_CreatePermissionTemplateResponse_descriptor;
+      }
+
+      public org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse getDefaultInstanceForType() {
+        return org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse.getDefaultInstance();
+      }
+
+      public org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse build() {
+        org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      public org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse buildPartial() {
+        org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse result = new org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse(this);
+        int from_bitField0_ = bitField0_;
+        int to_bitField0_ = 0;
+        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+          to_bitField0_ |= 0x00000001;
+        }
+        if (permissionTemplateBuilder_ == null) {
+          result.permissionTemplate_ = permissionTemplate_;
+        } else {
+          result.permissionTemplate_ = permissionTemplateBuilder_.build();
+        }
+        result.bitField0_ = to_bitField0_;
+        onBuilt();
+        return result;
+      }
+
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse) {
+          return mergeFrom((org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse other) {
+        if (other == org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse.getDefaultInstance()) return this;
+        if (other.hasPermissionTemplate()) {
+          mergePermissionTemplate(other.getPermissionTemplate());
+        }
+        this.mergeUnknownFields(other.getUnknownFields());
+        return this;
+      }
+
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse) e.getUnfinishedMessage();
+          throw e;
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int bitField0_;
+
+      private org.sonarqube.ws.Permissions.PermissionTemplate permissionTemplate_ = org.sonarqube.ws.Permissions.PermissionTemplate.getDefaultInstance();
+      private com.google.protobuf.SingleFieldBuilder<
+          org.sonarqube.ws.Permissions.PermissionTemplate, org.sonarqube.ws.Permissions.PermissionTemplate.Builder, org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder> permissionTemplateBuilder_;
+      /**
+       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       */
+      public boolean hasPermissionTemplate() {
+        return ((bitField0_ & 0x00000001) == 0x00000001);
+      }
+      /**
+       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       */
+      public org.sonarqube.ws.Permissions.PermissionTemplate getPermissionTemplate() {
+        if (permissionTemplateBuilder_ == null) {
+          return permissionTemplate_;
+        } else {
+          return permissionTemplateBuilder_.getMessage();
+        }
+      }
+      /**
+       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       */
+      public Builder setPermissionTemplate(org.sonarqube.ws.Permissions.PermissionTemplate value) {
+        if (permissionTemplateBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          permissionTemplate_ = value;
+          onChanged();
+        } else {
+          permissionTemplateBuilder_.setMessage(value);
+        }
+        bitField0_ |= 0x00000001;
+        return this;
+      }
+      /**
+       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       */
+      public Builder setPermissionTemplate(
+          org.sonarqube.ws.Permissions.PermissionTemplate.Builder builderForValue) {
+        if (permissionTemplateBuilder_ == null) {
+          permissionTemplate_ = builderForValue.build();
+          onChanged();
+        } else {
+          permissionTemplateBuilder_.setMessage(builderForValue.build());
+        }
+        bitField0_ |= 0x00000001;
+        return this;
+      }
+      /**
+       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       */
+      public Builder mergePermissionTemplate(org.sonarqube.ws.Permissions.PermissionTemplate value) {
+        if (permissionTemplateBuilder_ == null) {
+          if (((bitField0_ & 0x00000001) == 0x00000001) &&
+              permissionTemplate_ != org.sonarqube.ws.Permissions.PermissionTemplate.getDefaultInstance()) {
+            permissionTemplate_ =
+              org.sonarqube.ws.Permissions.PermissionTemplate.newBuilder(permissionTemplate_).mergeFrom(value).buildPartial();
+          } else {
+            permissionTemplate_ = value;
+          }
+          onChanged();
+        } else {
+          permissionTemplateBuilder_.mergeFrom(value);
+        }
+        bitField0_ |= 0x00000001;
+        return this;
+      }
+      /**
+       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       */
+      public Builder clearPermissionTemplate() {
+        if (permissionTemplateBuilder_ == null) {
+          permissionTemplate_ = org.sonarqube.ws.Permissions.PermissionTemplate.getDefaultInstance();
+          onChanged();
+        } else {
+          permissionTemplateBuilder_.clear();
+        }
+        bitField0_ = (bitField0_ & ~0x00000001);
+        return this;
+      }
+      /**
+       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       */
+      public org.sonarqube.ws.Permissions.PermissionTemplate.Builder getPermissionTemplateBuilder() {
+        bitField0_ |= 0x00000001;
+        onChanged();
+        return getPermissionTemplateFieldBuilder().getBuilder();
+      }
+      /**
+       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       */
+      public org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder getPermissionTemplateOrBuilder() {
+        if (permissionTemplateBuilder_ != null) {
+          return permissionTemplateBuilder_.getMessageOrBuilder();
+        } else {
+          return permissionTemplate_;
+        }
+      }
+      /**
+       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       */
+      private com.google.protobuf.SingleFieldBuilder<
+          org.sonarqube.ws.Permissions.PermissionTemplate, org.sonarqube.ws.Permissions.PermissionTemplate.Builder, org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder> 
+          getPermissionTemplateFieldBuilder() {
+        if (permissionTemplateBuilder_ == null) {
+          permissionTemplateBuilder_ = new com.google.protobuf.SingleFieldBuilder<
+              org.sonarqube.ws.Permissions.PermissionTemplate, org.sonarqube.ws.Permissions.PermissionTemplate.Builder, org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder>(
+                  getPermissionTemplate(),
+                  getParentForChildren(),
+                  isClean());
+          permissionTemplate_ = null;
+        }
+        return permissionTemplateBuilder_;
+      }
+
+      // @@protoc_insertion_point(builder_scope:sonarqube.ws.permissions.CreatePermissionTemplateResponse)
+    }
+
+    static {
+      defaultInstance = new CreatePermissionTemplateResponse(true);
+      defaultInstance.initFields();
+    }
+
+    // @@protoc_insertion_point(class_scope:sonarqube.ws.permissions.CreatePermissionTemplateResponse)
+  }
+
+  public interface UpdatePermissionTemplateResponseOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:sonarqube.ws.permissions.UpdatePermissionTemplateResponse)
+      com.google.protobuf.MessageOrBuilder {
+
+    /**
+     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+     */
+    boolean hasPermissionTemplate();
+    /**
+     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+     */
+    org.sonarqube.ws.Permissions.PermissionTemplate getPermissionTemplate();
+    /**
+     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+     */
+    org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder getPermissionTemplateOrBuilder();
+  }
+  /**
+   * Protobuf type {@code sonarqube.ws.permissions.UpdatePermissionTemplateResponse}
+   */
+  public static final class UpdatePermissionTemplateResponse extends
+      com.google.protobuf.GeneratedMessage implements
+      // @@protoc_insertion_point(message_implements:sonarqube.ws.permissions.UpdatePermissionTemplateResponse)
+      UpdatePermissionTemplateResponseOrBuilder {
+    // Use UpdatePermissionTemplateResponse.newBuilder() to construct.
+    private UpdatePermissionTemplateResponse(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
+      super(builder);
+      this.unknownFields = builder.getUnknownFields();
+    }
+    private UpdatePermissionTemplateResponse(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
+
+    private static final UpdatePermissionTemplateResponse defaultInstance;
+    public static UpdatePermissionTemplateResponse getDefaultInstance() {
+      return defaultInstance;
+    }
+
+    public UpdatePermissionTemplateResponse getDefaultInstanceForType() {
+      return defaultInstance;
+    }
+
+    private final com.google.protobuf.UnknownFieldSet unknownFields;
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+        getUnknownFields() {
+      return this.unknownFields;
+    }
+    private UpdatePermissionTemplateResponse(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      initFields();
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            default: {
+              if (!parseUnknownField(input, unknownFields,
+                                     extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+            case 10: {
+              org.sonarqube.ws.Permissions.PermissionTemplate.Builder subBuilder = null;
+              if (((bitField0_ & 0x00000001) == 0x00000001)) {
+                subBuilder = permissionTemplate_.toBuilder();
+              }
+              permissionTemplate_ = input.readMessage(org.sonarqube.ws.Permissions.PermissionTemplate.PARSER, extensionRegistry);
+              if (subBuilder != null) {
+                subBuilder.mergeFrom(permissionTemplate_);
+                permissionTemplate_ = subBuilder.buildPartial();
+              }
+              bitField0_ |= 0x00000001;
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(this);
+      } catch (java.io.IOException e) {
+        throw new com.google.protobuf.InvalidProtocolBufferException(
+            e.getMessage()).setUnfinishedMessage(this);
+      } finally {
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_UpdatePermissionTemplateResponse_descriptor;
+    }
+
+    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_UpdatePermissionTemplateResponse_fieldAccessorTable
           .ensureFieldAccessorsInitialized(
-              org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse.class, org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse.Builder.class);
+              org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse.class, org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse.Builder.class);
     }
 
-    public static com.google.protobuf.Parser<CreatePermissionTemplateResponse> PARSER =
-        new com.google.protobuf.AbstractParser<CreatePermissionTemplateResponse>() {
-      public CreatePermissionTemplateResponse parsePartialFrom(
+    public static com.google.protobuf.Parser<UpdatePermissionTemplateResponse> PARSER =
+        new com.google.protobuf.AbstractParser<UpdatePermissionTemplateResponse>() {
+      public UpdatePermissionTemplateResponse parsePartialFrom(
           com.google.protobuf.CodedInputStream input,
           com.google.protobuf.ExtensionRegistryLite extensionRegistry)
           throws com.google.protobuf.InvalidProtocolBufferException {
-        return new CreatePermissionTemplateResponse(input, extensionRegistry);
+        return new UpdatePermissionTemplateResponse(input, extensionRegistry);
       }
     };
 
     @java.lang.Override
-    public com.google.protobuf.Parser<CreatePermissionTemplateResponse> getParserForType() {
+    public com.google.protobuf.Parser<UpdatePermissionTemplateResponse> getParserForType() {
       return PARSER;
     }
 
@@ -9197,53 +10143,53 @@ public final class Permissions {
       return super.writeReplace();
     }
 
-    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseFrom(
+    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseFrom(
         com.google.protobuf.ByteString data)
         throws com.google.protobuf.InvalidProtocolBufferException {
       return PARSER.parseFrom(data);
     }
-    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseFrom(
+    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseFrom(
         com.google.protobuf.ByteString data,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws com.google.protobuf.InvalidProtocolBufferException {
       return PARSER.parseFrom(data, extensionRegistry);
     }
-    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseFrom(byte[] data)
+    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseFrom(byte[] data)
         throws com.google.protobuf.InvalidProtocolBufferException {
       return PARSER.parseFrom(data);
     }
-    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseFrom(
+    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseFrom(
         byte[] data,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws com.google.protobuf.InvalidProtocolBufferException {
       return PARSER.parseFrom(data, extensionRegistry);
     }
-    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseFrom(java.io.InputStream input)
+    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseFrom(java.io.InputStream input)
         throws java.io.IOException {
       return PARSER.parseFrom(input);
     }
-    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseFrom(
+    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseFrom(
         java.io.InputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws java.io.IOException {
       return PARSER.parseFrom(input, extensionRegistry);
     }
-    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseDelimitedFrom(java.io.InputStream input)
+    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseDelimitedFrom(java.io.InputStream input)
         throws java.io.IOException {
       return PARSER.parseDelimitedFrom(input);
     }
-    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseDelimitedFrom(
+    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseDelimitedFrom(
         java.io.InputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws java.io.IOException {
       return PARSER.parseDelimitedFrom(input, extensionRegistry);
     }
-    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseFrom(
+    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseFrom(
         com.google.protobuf.CodedInputStream input)
         throws java.io.IOException {
       return PARSER.parseFrom(input);
     }
-    public static org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parseFrom(
+    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseFrom(
         com.google.protobuf.CodedInputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws java.io.IOException {
@@ -9252,7 +10198,7 @@ public final class Permissions {
 
     public static Builder newBuilder() { return Builder.create(); }
     public Builder newBuilderForType() { return newBuilder(); }
-    public static Builder newBuilder(org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse prototype) {
+    public static Builder newBuilder(org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse prototype) {
       return newBuilder().mergeFrom(prototype);
     }
     public Builder toBuilder() { return newBuilder(this); }
@@ -9264,25 +10210,25 @@ public final class Permissions {
       return builder;
     }
     /**
-     * Protobuf type {@code sonarqube.ws.permissions.CreatePermissionTemplateResponse}
+     * Protobuf type {@code sonarqube.ws.permissions.UpdatePermissionTemplateResponse}
      */
     public static final class Builder extends
         com.google.protobuf.GeneratedMessage.Builder<Builder> implements
-        // @@protoc_insertion_point(builder_implements:sonarqube.ws.permissions.CreatePermissionTemplateResponse)
-        org.sonarqube.ws.Permissions.CreatePermissionTemplateResponseOrBuilder {
+        // @@protoc_insertion_point(builder_implements:sonarqube.ws.permissions.UpdatePermissionTemplateResponse)
+        org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponseOrBuilder {
       public static final com.google.protobuf.Descriptors.Descriptor
           getDescriptor() {
-        return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_CreatePermissionTemplateResponse_descriptor;
+        return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_UpdatePermissionTemplateResponse_descriptor;
       }
 
       protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
           internalGetFieldAccessorTable() {
-        return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_CreatePermissionTemplateResponse_fieldAccessorTable
+        return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_UpdatePermissionTemplateResponse_fieldAccessorTable
             .ensureFieldAccessorsInitialized(
-                org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse.class, org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse.Builder.class);
+                org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse.class, org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse.Builder.class);
       }
 
-      // Construct using org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse.newBuilder()
+      // Construct using org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse.newBuilder()
       private Builder() {
         maybeForceBuilderInitialization();
       }
@@ -9318,23 +10264,23 @@ public final class Permissions {
 
       public com.google.protobuf.Descriptors.Descriptor
           getDescriptorForType() {
-        return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_CreatePermissionTemplateResponse_descriptor;
+        return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_UpdatePermissionTemplateResponse_descriptor;
       }
 
-      public org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse getDefaultInstanceForType() {
-        return org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse.getDefaultInstance();
+      public org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse getDefaultInstanceForType() {
+        return org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse.getDefaultInstance();
       }
 
-      public org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse build() {
-        org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse result = buildPartial();
+      public org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse build() {
+        org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse result = buildPartial();
         if (!result.isInitialized()) {
           throw newUninitializedMessageException(result);
         }
         return result;
       }
 
-      public org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse buildPartial() {
-        org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse result = new org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse(this);
+      public org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse buildPartial() {
+        org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse result = new org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse(this);
         int from_bitField0_ = bitField0_;
         int to_bitField0_ = 0;
         if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
@@ -9351,16 +10297,16 @@ public final class Permissions {
       }
 
       public Builder mergeFrom(com.google.protobuf.Message other) {
-        if (other instanceof org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse) {
-          return mergeFrom((org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse)other);
+        if (other instanceof org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse) {
+          return mergeFrom((org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse)other);
         } else {
           super.mergeFrom(other);
           return this;
         }
       }
 
-      public Builder mergeFrom(org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse other) {
-        if (other == org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse.getDefaultInstance()) return this;
+      public Builder mergeFrom(org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse other) {
+        if (other == org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse.getDefaultInstance()) return this;
         if (other.hasPermissionTemplate()) {
           mergePermissionTemplate(other.getPermissionTemplate());
         }
@@ -9376,11 +10322,11 @@ public final class Permissions {
           com.google.protobuf.CodedInputStream input,
           com.google.protobuf.ExtensionRegistryLite extensionRegistry)
           throws java.io.IOException {
-        org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse parsedMessage = null;
+        org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parsedMessage = null;
         try {
           parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
         } catch (com.google.protobuf.InvalidProtocolBufferException e) {
-          parsedMessage = (org.sonarqube.ws.Permissions.CreatePermissionTemplateResponse) e.getUnfinishedMessage();
+          parsedMessage = (org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse) e.getUnfinishedMessage();
           throw e;
         } finally {
           if (parsedMessage != null) {
@@ -9507,54 +10453,89 @@ public final class Permissions {
         return permissionTemplateBuilder_;
       }
 
-      // @@protoc_insertion_point(builder_scope:sonarqube.ws.permissions.CreatePermissionTemplateResponse)
+      // @@protoc_insertion_point(builder_scope:sonarqube.ws.permissions.UpdatePermissionTemplateResponse)
     }
 
     static {
-      defaultInstance = new CreatePermissionTemplateResponse(true);
+      defaultInstance = new UpdatePermissionTemplateResponse(true);
       defaultInstance.initFields();
     }
 
-    // @@protoc_insertion_point(class_scope:sonarqube.ws.permissions.CreatePermissionTemplateResponse)
+    // @@protoc_insertion_point(class_scope:sonarqube.ws.permissions.UpdatePermissionTemplateResponse)
   }
 
-  public interface UpdatePermissionTemplateResponseOrBuilder extends
-      // @@protoc_insertion_point(interface_extends:sonarqube.ws.permissions.UpdatePermissionTemplateResponse)
+  public interface SearchTemplatesResponseOrBuilder extends
+      // @@protoc_insertion_point(interface_extends:sonarqube.ws.permissions.SearchTemplatesResponse)
       com.google.protobuf.MessageOrBuilder {
 
     /**
-     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+     * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
      */
-    boolean hasPermissionTemplate();
+    java.util.List<org.sonarqube.ws.Permissions.PermissionTemplate> 
+        getPermissionTemplatesList();
     /**
-     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+     * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
      */
-    org.sonarqube.ws.Permissions.PermissionTemplate getPermissionTemplate();
+    org.sonarqube.ws.Permissions.PermissionTemplate getPermissionTemplates(int index);
     /**
-     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+     * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
      */
-    org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder getPermissionTemplateOrBuilder();
+    int getPermissionTemplatesCount();
+    /**
+     * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+     */
+    java.util.List<? extends org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder> 
+        getPermissionTemplatesOrBuilderList();
+    /**
+     * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+     */
+    org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder getPermissionTemplatesOrBuilder(
+        int index);
+
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+     */
+    java.util.List<org.sonarqube.ws.Permissions.Permission> 
+        getPermissionsList();
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+     */
+    org.sonarqube.ws.Permissions.Permission getPermissions(int index);
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+     */
+    int getPermissionsCount();
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+     */
+    java.util.List<? extends org.sonarqube.ws.Permissions.PermissionOrBuilder> 
+        getPermissionsOrBuilderList();
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+     */
+    org.sonarqube.ws.Permissions.PermissionOrBuilder getPermissionsOrBuilder(
+        int index);
   }
   /**
-   * Protobuf type {@code sonarqube.ws.permissions.UpdatePermissionTemplateResponse}
+   * Protobuf type {@code sonarqube.ws.permissions.SearchTemplatesResponse}
    */
-  public static final class UpdatePermissionTemplateResponse extends
+  public static final class SearchTemplatesResponse extends
       com.google.protobuf.GeneratedMessage implements
-      // @@protoc_insertion_point(message_implements:sonarqube.ws.permissions.UpdatePermissionTemplateResponse)
-      UpdatePermissionTemplateResponseOrBuilder {
-    // Use UpdatePermissionTemplateResponse.newBuilder() to construct.
-    private UpdatePermissionTemplateResponse(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
+      // @@protoc_insertion_point(message_implements:sonarqube.ws.permissions.SearchTemplatesResponse)
+      SearchTemplatesResponseOrBuilder {
+    // Use SearchTemplatesResponse.newBuilder() to construct.
+    private SearchTemplatesResponse(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
       super(builder);
       this.unknownFields = builder.getUnknownFields();
     }
-    private UpdatePermissionTemplateResponse(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
+    private SearchTemplatesResponse(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
 
-    private static final UpdatePermissionTemplateResponse defaultInstance;
-    public static UpdatePermissionTemplateResponse getDefaultInstance() {
+    private static final SearchTemplatesResponse defaultInstance;
+    public static SearchTemplatesResponse getDefaultInstance() {
       return defaultInstance;
     }
 
-    public UpdatePermissionTemplateResponse getDefaultInstanceForType() {
+    public SearchTemplatesResponse getDefaultInstanceForType() {
       return defaultInstance;
     }
 
@@ -9564,7 +10545,7 @@ public final class Permissions {
         getUnknownFields() {
       return this.unknownFields;
     }
-    private UpdatePermissionTemplateResponse(
+    private SearchTemplatesResponse(
         com.google.protobuf.CodedInputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws com.google.protobuf.InvalidProtocolBufferException {
@@ -9587,17 +10568,20 @@ public final class Permissions {
               }
               break;
             }
-            case 10: {
-              org.sonarqube.ws.Permissions.PermissionTemplate.Builder subBuilder = null;
-              if (((bitField0_ & 0x00000001) == 0x00000001)) {
-                subBuilder = permissionTemplate_.toBuilder();
+            case 18: {
+              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
+                permissionTemplates_ = new java.util.ArrayList<org.sonarqube.ws.Permissions.PermissionTemplate>();
+                mutable_bitField0_ |= 0x00000001;
               }
-              permissionTemplate_ = input.readMessage(org.sonarqube.ws.Permissions.PermissionTemplate.PARSER, extensionRegistry);
-              if (subBuilder != null) {
-                subBuilder.mergeFrom(permissionTemplate_);
-                permissionTemplate_ = subBuilder.buildPartial();
+              permissionTemplates_.add(input.readMessage(org.sonarqube.ws.Permissions.PermissionTemplate.PARSER, extensionRegistry));
+              break;
+            }
+            case 26: {
+              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {
+                permissions_ = new java.util.ArrayList<org.sonarqube.ws.Permissions.Permission>();
+                mutable_bitField0_ |= 0x00000002;
               }
-              bitField0_ |= 0x00000001;
+              permissions_.add(input.readMessage(org.sonarqube.ws.Permissions.Permission.PARSER, extensionRegistry));
               break;
             }
           }
@@ -9608,61 +10592,116 @@ public final class Permissions {
         throw new com.google.protobuf.InvalidProtocolBufferException(
             e.getMessage()).setUnfinishedMessage(this);
       } finally {
+        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {
+          permissionTemplates_ = java.util.Collections.unmodifiableList(permissionTemplates_);
+        }
+        if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {
+          permissions_ = java.util.Collections.unmodifiableList(permissions_);
+        }
         this.unknownFields = unknownFields.build();
         makeExtensionsImmutable();
       }
     }
     public static final com.google.protobuf.Descriptors.Descriptor
         getDescriptor() {
-      return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_UpdatePermissionTemplateResponse_descriptor;
+      return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_SearchTemplatesResponse_descriptor;
     }
 
     protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
         internalGetFieldAccessorTable() {
-      return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_UpdatePermissionTemplateResponse_fieldAccessorTable
+      return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_SearchTemplatesResponse_fieldAccessorTable
           .ensureFieldAccessorsInitialized(
-              org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse.class, org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse.Builder.class);
+              org.sonarqube.ws.Permissions.SearchTemplatesResponse.class, org.sonarqube.ws.Permissions.SearchTemplatesResponse.Builder.class);
     }
 
-    public static com.google.protobuf.Parser<UpdatePermissionTemplateResponse> PARSER =
-        new com.google.protobuf.AbstractParser<UpdatePermissionTemplateResponse>() {
-      public UpdatePermissionTemplateResponse parsePartialFrom(
+    public static com.google.protobuf.Parser<SearchTemplatesResponse> PARSER =
+        new com.google.protobuf.AbstractParser<SearchTemplatesResponse>() {
+      public SearchTemplatesResponse parsePartialFrom(
           com.google.protobuf.CodedInputStream input,
           com.google.protobuf.ExtensionRegistryLite extensionRegistry)
           throws com.google.protobuf.InvalidProtocolBufferException {
-        return new UpdatePermissionTemplateResponse(input, extensionRegistry);
+        return new SearchTemplatesResponse(input, extensionRegistry);
       }
     };
 
     @java.lang.Override
-    public com.google.protobuf.Parser<UpdatePermissionTemplateResponse> getParserForType() {
+    public com.google.protobuf.Parser<SearchTemplatesResponse> getParserForType() {
       return PARSER;
     }
 
-    private int bitField0_;
-    public static final int PERMISSIONTEMPLATE_FIELD_NUMBER = 1;
-    private org.sonarqube.ws.Permissions.PermissionTemplate permissionTemplate_;
+    public static final int PERMISSIONTEMPLATES_FIELD_NUMBER = 2;
+    private java.util.List<org.sonarqube.ws.Permissions.PermissionTemplate> permissionTemplates_;
     /**
-     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+     * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
      */
-    public boolean hasPermissionTemplate() {
-      return ((bitField0_ & 0x00000001) == 0x00000001);
+    public java.util.List<org.sonarqube.ws.Permissions.PermissionTemplate> getPermissionTemplatesList() {
+      return permissionTemplates_;
     }
     /**
-     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+     * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
      */
-    public org.sonarqube.ws.Permissions.PermissionTemplate getPermissionTemplate() {
-      return permissionTemplate_;
+    public java.util.List<? extends org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder> 
+        getPermissionTemplatesOrBuilderList() {
+      return permissionTemplates_;
     }
     /**
-     * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+     * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
      */
-    public org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder getPermissionTemplateOrBuilder() {
-      return permissionTemplate_;
+    public int getPermissionTemplatesCount() {
+      return permissionTemplates_.size();
+    }
+    /**
+     * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+     */
+    public org.sonarqube.ws.Permissions.PermissionTemplate getPermissionTemplates(int index) {
+      return permissionTemplates_.get(index);
+    }
+    /**
+     * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+     */
+    public org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder getPermissionTemplatesOrBuilder(
+        int index) {
+      return permissionTemplates_.get(index);
+    }
+
+    public static final int PERMISSIONS_FIELD_NUMBER = 3;
+    private java.util.List<org.sonarqube.ws.Permissions.Permission> permissions_;
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+     */
+    public java.util.List<org.sonarqube.ws.Permissions.Permission> getPermissionsList() {
+      return permissions_;
+    }
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+     */
+    public java.util.List<? extends org.sonarqube.ws.Permissions.PermissionOrBuilder> 
+        getPermissionsOrBuilderList() {
+      return permissions_;
+    }
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+     */
+    public int getPermissionsCount() {
+      return permissions_.size();
+    }
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+     */
+    public org.sonarqube.ws.Permissions.Permission getPermissions(int index) {
+      return permissions_.get(index);
+    }
+    /**
+     * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+     */
+    public org.sonarqube.ws.Permissions.PermissionOrBuilder getPermissionsOrBuilder(
+        int index) {
+      return permissions_.get(index);
     }
 
     private void initFields() {
-      permissionTemplate_ = org.sonarqube.ws.Permissions.PermissionTemplate.getDefaultInstance();
+      permissionTemplates_ = java.util.Collections.emptyList();
+      permissions_ = java.util.Collections.emptyList();
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -9677,8 +10716,11 @@ public final class Permissions {
     public void writeTo(com.google.protobuf.CodedOutputStream output)
                         throws java.io.IOException {
       getSerializedSize();
-      if (((bitField0_ & 0x00000001) == 0x00000001)) {
-        output.writeMessage(1, permissionTemplate_);
+      for (int i = 0; i < permissionTemplates_.size(); i++) {
+        output.writeMessage(2, permissionTemplates_.get(i));
+      }
+      for (int i = 0; i < permissions_.size(); i++) {
+        output.writeMessage(3, permissions_.get(i));
       }
       getUnknownFields().writeTo(output);
     }
@@ -9689,9 +10731,13 @@ public final class Permissions {
       if (size != -1) return size;
 
       size = 0;
-      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+      for (int i = 0; i < permissionTemplates_.size(); i++) {
         size += com.google.protobuf.CodedOutputStream
-          .computeMessageSize(1, permissionTemplate_);
+          .computeMessageSize(2, permissionTemplates_.get(i));
+      }
+      for (int i = 0; i < permissions_.size(); i++) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(3, permissions_.get(i));
       }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
@@ -9705,53 +10751,53 @@ public final class Permissions {
       return super.writeReplace();
     }
 
-    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseFrom(
+    public static org.sonarqube.ws.Permissions.SearchTemplatesResponse parseFrom(
         com.google.protobuf.ByteString data)
         throws com.google.protobuf.InvalidProtocolBufferException {
       return PARSER.parseFrom(data);
     }
-    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseFrom(
+    public static org.sonarqube.ws.Permissions.SearchTemplatesResponse parseFrom(
         com.google.protobuf.ByteString data,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws com.google.protobuf.InvalidProtocolBufferException {
       return PARSER.parseFrom(data, extensionRegistry);
     }
-    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseFrom(byte[] data)
+    public static org.sonarqube.ws.Permissions.SearchTemplatesResponse parseFrom(byte[] data)
         throws com.google.protobuf.InvalidProtocolBufferException {
       return PARSER.parseFrom(data);
     }
-    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseFrom(
+    public static org.sonarqube.ws.Permissions.SearchTemplatesResponse parseFrom(
         byte[] data,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws com.google.protobuf.InvalidProtocolBufferException {
       return PARSER.parseFrom(data, extensionRegistry);
     }
-    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseFrom(java.io.InputStream input)
+    public static org.sonarqube.ws.Permissions.SearchTemplatesResponse parseFrom(java.io.InputStream input)
         throws java.io.IOException {
       return PARSER.parseFrom(input);
     }
-    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseFrom(
+    public static org.sonarqube.ws.Permissions.SearchTemplatesResponse parseFrom(
         java.io.InputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws java.io.IOException {
       return PARSER.parseFrom(input, extensionRegistry);
     }
-    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseDelimitedFrom(java.io.InputStream input)
+    public static org.sonarqube.ws.Permissions.SearchTemplatesResponse parseDelimitedFrom(java.io.InputStream input)
         throws java.io.IOException {
       return PARSER.parseDelimitedFrom(input);
     }
-    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseDelimitedFrom(
+    public static org.sonarqube.ws.Permissions.SearchTemplatesResponse parseDelimitedFrom(
         java.io.InputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws java.io.IOException {
       return PARSER.parseDelimitedFrom(input, extensionRegistry);
     }
-    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseFrom(
+    public static org.sonarqube.ws.Permissions.SearchTemplatesResponse parseFrom(
         com.google.protobuf.CodedInputStream input)
         throws java.io.IOException {
       return PARSER.parseFrom(input);
     }
-    public static org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parseFrom(
+    public static org.sonarqube.ws.Permissions.SearchTemplatesResponse parseFrom(
         com.google.protobuf.CodedInputStream input,
         com.google.protobuf.ExtensionRegistryLite extensionRegistry)
         throws java.io.IOException {
@@ -9760,7 +10806,7 @@ public final class Permissions {
 
     public static Builder newBuilder() { return Builder.create(); }
     public Builder newBuilderForType() { return newBuilder(); }
-    public static Builder newBuilder(org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse prototype) {
+    public static Builder newBuilder(org.sonarqube.ws.Permissions.SearchTemplatesResponse prototype) {
       return newBuilder().mergeFrom(prototype);
     }
     public Builder toBuilder() { return newBuilder(this); }
@@ -9772,258 +10818,686 @@ public final class Permissions {
       return builder;
     }
     /**
-     * Protobuf type {@code sonarqube.ws.permissions.UpdatePermissionTemplateResponse}
+     * Protobuf type {@code sonarqube.ws.permissions.SearchTemplatesResponse}
      */
     public static final class Builder extends
         com.google.protobuf.GeneratedMessage.Builder<Builder> implements
-        // @@protoc_insertion_point(builder_implements:sonarqube.ws.permissions.UpdatePermissionTemplateResponse)
-        org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponseOrBuilder {
+        // @@protoc_insertion_point(builder_implements:sonarqube.ws.permissions.SearchTemplatesResponse)
+        org.sonarqube.ws.Permissions.SearchTemplatesResponseOrBuilder {
       public static final com.google.protobuf.Descriptors.Descriptor
           getDescriptor() {
-        return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_UpdatePermissionTemplateResponse_descriptor;
+        return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_SearchTemplatesResponse_descriptor;
+      }
+
+      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_SearchTemplatesResponse_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                org.sonarqube.ws.Permissions.SearchTemplatesResponse.class, org.sonarqube.ws.Permissions.SearchTemplatesResponse.Builder.class);
+      }
+
+      // Construct using org.sonarqube.ws.Permissions.SearchTemplatesResponse.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+          getPermissionTemplatesFieldBuilder();
+          getPermissionsFieldBuilder();
+        }
+      }
+      private static Builder create() {
+        return new Builder();
+      }
+
+      public Builder clear() {
+        super.clear();
+        if (permissionTemplatesBuilder_ == null) {
+          permissionTemplates_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000001);
+        } else {
+          permissionTemplatesBuilder_.clear();
+        }
+        if (permissionsBuilder_ == null) {
+          permissions_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000002);
+        } else {
+          permissionsBuilder_.clear();
+        }
+        return this;
+      }
+
+      public Builder clone() {
+        return create().mergeFrom(buildPartial());
+      }
+
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_SearchTemplatesResponse_descriptor;
+      }
+
+      public org.sonarqube.ws.Permissions.SearchTemplatesResponse getDefaultInstanceForType() {
+        return org.sonarqube.ws.Permissions.SearchTemplatesResponse.getDefaultInstance();
+      }
+
+      public org.sonarqube.ws.Permissions.SearchTemplatesResponse build() {
+        org.sonarqube.ws.Permissions.SearchTemplatesResponse result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      public org.sonarqube.ws.Permissions.SearchTemplatesResponse buildPartial() {
+        org.sonarqube.ws.Permissions.SearchTemplatesResponse result = new org.sonarqube.ws.Permissions.SearchTemplatesResponse(this);
+        int from_bitField0_ = bitField0_;
+        if (permissionTemplatesBuilder_ == null) {
+          if (((bitField0_ & 0x00000001) == 0x00000001)) {
+            permissionTemplates_ = java.util.Collections.unmodifiableList(permissionTemplates_);
+            bitField0_ = (bitField0_ & ~0x00000001);
+          }
+          result.permissionTemplates_ = permissionTemplates_;
+        } else {
+          result.permissionTemplates_ = permissionTemplatesBuilder_.build();
+        }
+        if (permissionsBuilder_ == null) {
+          if (((bitField0_ & 0x00000002) == 0x00000002)) {
+            permissions_ = java.util.Collections.unmodifiableList(permissions_);
+            bitField0_ = (bitField0_ & ~0x00000002);
+          }
+          result.permissions_ = permissions_;
+        } else {
+          result.permissions_ = permissionsBuilder_.build();
+        }
+        onBuilt();
+        return result;
       }
 
-      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
-          internalGetFieldAccessorTable() {
-        return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_UpdatePermissionTemplateResponse_fieldAccessorTable
-            .ensureFieldAccessorsInitialized(
-                org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse.class, org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse.Builder.class);
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof org.sonarqube.ws.Permissions.SearchTemplatesResponse) {
+          return mergeFrom((org.sonarqube.ws.Permissions.SearchTemplatesResponse)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
       }
 
-      // Construct using org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse.newBuilder()
-      private Builder() {
-        maybeForceBuilderInitialization();
+      public Builder mergeFrom(org.sonarqube.ws.Permissions.SearchTemplatesResponse other) {
+        if (other == org.sonarqube.ws.Permissions.SearchTemplatesResponse.getDefaultInstance()) return this;
+        if (permissionTemplatesBuilder_ == null) {
+          if (!other.permissionTemplates_.isEmpty()) {
+            if (permissionTemplates_.isEmpty()) {
+              permissionTemplates_ = other.permissionTemplates_;
+              bitField0_ = (bitField0_ & ~0x00000001);
+            } else {
+              ensurePermissionTemplatesIsMutable();
+              permissionTemplates_.addAll(other.permissionTemplates_);
+            }
+            onChanged();
+          }
+        } else {
+          if (!other.permissionTemplates_.isEmpty()) {
+            if (permissionTemplatesBuilder_.isEmpty()) {
+              permissionTemplatesBuilder_.dispose();
+              permissionTemplatesBuilder_ = null;
+              permissionTemplates_ = other.permissionTemplates_;
+              bitField0_ = (bitField0_ & ~0x00000001);
+              permissionTemplatesBuilder_ = 
+                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
+                   getPermissionTemplatesFieldBuilder() : null;
+            } else {
+              permissionTemplatesBuilder_.addAllMessages(other.permissionTemplates_);
+            }
+          }
+        }
+        if (permissionsBuilder_ == null) {
+          if (!other.permissions_.isEmpty()) {
+            if (permissions_.isEmpty()) {
+              permissions_ = other.permissions_;
+              bitField0_ = (bitField0_ & ~0x00000002);
+            } else {
+              ensurePermissionsIsMutable();
+              permissions_.addAll(other.permissions_);
+            }
+            onChanged();
+          }
+        } else {
+          if (!other.permissions_.isEmpty()) {
+            if (permissionsBuilder_.isEmpty()) {
+              permissionsBuilder_.dispose();
+              permissionsBuilder_ = null;
+              permissions_ = other.permissions_;
+              bitField0_ = (bitField0_ & ~0x00000002);
+              permissionsBuilder_ = 
+                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
+                   getPermissionsFieldBuilder() : null;
+            } else {
+              permissionsBuilder_.addAllMessages(other.permissions_);
+            }
+          }
+        }
+        this.mergeUnknownFields(other.getUnknownFields());
+        return this;
       }
 
-      private Builder(
-          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
-        super(parent);
-        maybeForceBuilderInitialization();
+      public final boolean isInitialized() {
+        return true;
       }
-      private void maybeForceBuilderInitialization() {
-        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
-          getPermissionTemplateFieldBuilder();
+
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        org.sonarqube.ws.Permissions.SearchTemplatesResponse parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (org.sonarqube.ws.Permissions.SearchTemplatesResponse) e.getUnfinishedMessage();
+          throw e;
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
         }
+        return this;
       }
-      private static Builder create() {
-        return new Builder();
+      private int bitField0_;
+
+      private java.util.List<org.sonarqube.ws.Permissions.PermissionTemplate> permissionTemplates_ =
+        java.util.Collections.emptyList();
+      private void ensurePermissionTemplatesIsMutable() {
+        if (!((bitField0_ & 0x00000001) == 0x00000001)) {
+          permissionTemplates_ = new java.util.ArrayList<org.sonarqube.ws.Permissions.PermissionTemplate>(permissionTemplates_);
+          bitField0_ |= 0x00000001;
+         }
       }
 
-      public Builder clear() {
-        super.clear();
-        if (permissionTemplateBuilder_ == null) {
-          permissionTemplate_ = org.sonarqube.ws.Permissions.PermissionTemplate.getDefaultInstance();
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonarqube.ws.Permissions.PermissionTemplate, org.sonarqube.ws.Permissions.PermissionTemplate.Builder, org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder> permissionTemplatesBuilder_;
+
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public java.util.List<org.sonarqube.ws.Permissions.PermissionTemplate> getPermissionTemplatesList() {
+        if (permissionTemplatesBuilder_ == null) {
+          return java.util.Collections.unmodifiableList(permissionTemplates_);
         } else {
-          permissionTemplateBuilder_.clear();
+          return permissionTemplatesBuilder_.getMessageList();
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public int getPermissionTemplatesCount() {
+        if (permissionTemplatesBuilder_ == null) {
+          return permissionTemplates_.size();
+        } else {
+          return permissionTemplatesBuilder_.getCount();
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public org.sonarqube.ws.Permissions.PermissionTemplate getPermissionTemplates(int index) {
+        if (permissionTemplatesBuilder_ == null) {
+          return permissionTemplates_.get(index);
+        } else {
+          return permissionTemplatesBuilder_.getMessage(index);
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public Builder setPermissionTemplates(
+          int index, org.sonarqube.ws.Permissions.PermissionTemplate value) {
+        if (permissionTemplatesBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensurePermissionTemplatesIsMutable();
+          permissionTemplates_.set(index, value);
+          onChanged();
+        } else {
+          permissionTemplatesBuilder_.setMessage(index, value);
         }
-        bitField0_ = (bitField0_ & ~0x00000001);
         return this;
       }
-
-      public Builder clone() {
-        return create().mergeFrom(buildPartial());
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public Builder setPermissionTemplates(
+          int index, org.sonarqube.ws.Permissions.PermissionTemplate.Builder builderForValue) {
+        if (permissionTemplatesBuilder_ == null) {
+          ensurePermissionTemplatesIsMutable();
+          permissionTemplates_.set(index, builderForValue.build());
+          onChanged();
+        } else {
+          permissionTemplatesBuilder_.setMessage(index, builderForValue.build());
+        }
+        return this;
       }
-
-      public com.google.protobuf.Descriptors.Descriptor
-          getDescriptorForType() {
-        return org.sonarqube.ws.Permissions.internal_static_sonarqube_ws_permissions_UpdatePermissionTemplateResponse_descriptor;
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public Builder addPermissionTemplates(org.sonarqube.ws.Permissions.PermissionTemplate value) {
+        if (permissionTemplatesBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensurePermissionTemplatesIsMutable();
+          permissionTemplates_.add(value);
+          onChanged();
+        } else {
+          permissionTemplatesBuilder_.addMessage(value);
+        }
+        return this;
       }
-
-      public org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse getDefaultInstanceForType() {
-        return org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse.getDefaultInstance();
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public Builder addPermissionTemplates(
+          int index, org.sonarqube.ws.Permissions.PermissionTemplate value) {
+        if (permissionTemplatesBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensurePermissionTemplatesIsMutable();
+          permissionTemplates_.add(index, value);
+          onChanged();
+        } else {
+          permissionTemplatesBuilder_.addMessage(index, value);
+        }
+        return this;
       }
-
-      public org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse build() {
-        org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse result = buildPartial();
-        if (!result.isInitialized()) {
-          throw newUninitializedMessageException(result);
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public Builder addPermissionTemplates(
+          org.sonarqube.ws.Permissions.PermissionTemplate.Builder builderForValue) {
+        if (permissionTemplatesBuilder_ == null) {
+          ensurePermissionTemplatesIsMutable();
+          permissionTemplates_.add(builderForValue.build());
+          onChanged();
+        } else {
+          permissionTemplatesBuilder_.addMessage(builderForValue.build());
         }
-        return result;
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public Builder addPermissionTemplates(
+          int index, org.sonarqube.ws.Permissions.PermissionTemplate.Builder builderForValue) {
+        if (permissionTemplatesBuilder_ == null) {
+          ensurePermissionTemplatesIsMutable();
+          permissionTemplates_.add(index, builderForValue.build());
+          onChanged();
+        } else {
+          permissionTemplatesBuilder_.addMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public Builder addAllPermissionTemplates(
+          java.lang.Iterable<? extends org.sonarqube.ws.Permissions.PermissionTemplate> values) {
+        if (permissionTemplatesBuilder_ == null) {
+          ensurePermissionTemplatesIsMutable();
+          com.google.protobuf.AbstractMessageLite.Builder.addAll(
+              values, permissionTemplates_);
+          onChanged();
+        } else {
+          permissionTemplatesBuilder_.addAllMessages(values);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public Builder clearPermissionTemplates() {
+        if (permissionTemplatesBuilder_ == null) {
+          permissionTemplates_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000001);
+          onChanged();
+        } else {
+          permissionTemplatesBuilder_.clear();
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public Builder removePermissionTemplates(int index) {
+        if (permissionTemplatesBuilder_ == null) {
+          ensurePermissionTemplatesIsMutable();
+          permissionTemplates_.remove(index);
+          onChanged();
+        } else {
+          permissionTemplatesBuilder_.remove(index);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public org.sonarqube.ws.Permissions.PermissionTemplate.Builder getPermissionTemplatesBuilder(
+          int index) {
+        return getPermissionTemplatesFieldBuilder().getBuilder(index);
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder getPermissionTemplatesOrBuilder(
+          int index) {
+        if (permissionTemplatesBuilder_ == null) {
+          return permissionTemplates_.get(index);  } else {
+          return permissionTemplatesBuilder_.getMessageOrBuilder(index);
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public java.util.List<? extends org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder> 
+           getPermissionTemplatesOrBuilderList() {
+        if (permissionTemplatesBuilder_ != null) {
+          return permissionTemplatesBuilder_.getMessageOrBuilderList();
+        } else {
+          return java.util.Collections.unmodifiableList(permissionTemplates_);
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public org.sonarqube.ws.Permissions.PermissionTemplate.Builder addPermissionTemplatesBuilder() {
+        return getPermissionTemplatesFieldBuilder().addBuilder(
+            org.sonarqube.ws.Permissions.PermissionTemplate.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public org.sonarqube.ws.Permissions.PermissionTemplate.Builder addPermissionTemplatesBuilder(
+          int index) {
+        return getPermissionTemplatesFieldBuilder().addBuilder(
+            index, org.sonarqube.ws.Permissions.PermissionTemplate.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.PermissionTemplate permissionTemplates = 2;</code>
+       */
+      public java.util.List<org.sonarqube.ws.Permissions.PermissionTemplate.Builder> 
+           getPermissionTemplatesBuilderList() {
+        return getPermissionTemplatesFieldBuilder().getBuilderList();
+      }
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonarqube.ws.Permissions.PermissionTemplate, org.sonarqube.ws.Permissions.PermissionTemplate.Builder, org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder> 
+          getPermissionTemplatesFieldBuilder() {
+        if (permissionTemplatesBuilder_ == null) {
+          permissionTemplatesBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
+              org.sonarqube.ws.Permissions.PermissionTemplate, org.sonarqube.ws.Permissions.PermissionTemplate.Builder, org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder>(
+                  permissionTemplates_,
+                  ((bitField0_ & 0x00000001) == 0x00000001),
+                  getParentForChildren(),
+                  isClean());
+          permissionTemplates_ = null;
+        }
+        return permissionTemplatesBuilder_;
       }
 
-      public org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse buildPartial() {
-        org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse result = new org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse(this);
-        int from_bitField0_ = bitField0_;
-        int to_bitField0_ = 0;
-        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
-          to_bitField0_ |= 0x00000001;
+      private java.util.List<org.sonarqube.ws.Permissions.Permission> permissions_ =
+        java.util.Collections.emptyList();
+      private void ensurePermissionsIsMutable() {
+        if (!((bitField0_ & 0x00000002) == 0x00000002)) {
+          permissions_ = new java.util.ArrayList<org.sonarqube.ws.Permissions.Permission>(permissions_);
+          bitField0_ |= 0x00000002;
+         }
+      }
+
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonarqube.ws.Permissions.Permission, org.sonarqube.ws.Permissions.Permission.Builder, org.sonarqube.ws.Permissions.PermissionOrBuilder> permissionsBuilder_;
+
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+       */
+      public java.util.List<org.sonarqube.ws.Permissions.Permission> getPermissionsList() {
+        if (permissionsBuilder_ == null) {
+          return java.util.Collections.unmodifiableList(permissions_);
+        } else {
+          return permissionsBuilder_.getMessageList();
         }
-        if (permissionTemplateBuilder_ == null) {
-          result.permissionTemplate_ = permissionTemplate_;
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+       */
+      public int getPermissionsCount() {
+        if (permissionsBuilder_ == null) {
+          return permissions_.size();
         } else {
-          result.permissionTemplate_ = permissionTemplateBuilder_.build();
+          return permissionsBuilder_.getCount();
         }
-        result.bitField0_ = to_bitField0_;
-        onBuilt();
-        return result;
       }
-
-      public Builder mergeFrom(com.google.protobuf.Message other) {
-        if (other instanceof org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse) {
-          return mergeFrom((org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse)other);
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+       */
+      public org.sonarqube.ws.Permissions.Permission getPermissions(int index) {
+        if (permissionsBuilder_ == null) {
+          return permissions_.get(index);
         } else {
-          super.mergeFrom(other);
-          return this;
+          return permissionsBuilder_.getMessage(index);
         }
       }
-
-      public Builder mergeFrom(org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse other) {
-        if (other == org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse.getDefaultInstance()) return this;
-        if (other.hasPermissionTemplate()) {
-          mergePermissionTemplate(other.getPermissionTemplate());
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+       */
+      public Builder setPermissions(
+          int index, org.sonarqube.ws.Permissions.Permission value) {
+        if (permissionsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensurePermissionsIsMutable();
+          permissions_.set(index, value);
+          onChanged();
+        } else {
+          permissionsBuilder_.setMessage(index, value);
         }
-        this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
-
-      public final boolean isInitialized() {
-        return true;
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+       */
+      public Builder setPermissions(
+          int index, org.sonarqube.ws.Permissions.Permission.Builder builderForValue) {
+        if (permissionsBuilder_ == null) {
+          ensurePermissionsIsMutable();
+          permissions_.set(index, builderForValue.build());
+          onChanged();
+        } else {
+          permissionsBuilder_.setMessage(index, builderForValue.build());
+        }
+        return this;
       }
-
-      public Builder mergeFrom(
-          com.google.protobuf.CodedInputStream input,
-          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
-          throws java.io.IOException {
-        org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse parsedMessage = null;
-        try {
-          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
-        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
-          parsedMessage = (org.sonarqube.ws.Permissions.UpdatePermissionTemplateResponse) e.getUnfinishedMessage();
-          throw e;
-        } finally {
-          if (parsedMessage != null) {
-            mergeFrom(parsedMessage);
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+       */
+      public Builder addPermissions(org.sonarqube.ws.Permissions.Permission value) {
+        if (permissionsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
           }
+          ensurePermissionsIsMutable();
+          permissions_.add(value);
+          onChanged();
+        } else {
+          permissionsBuilder_.addMessage(value);
         }
         return this;
       }
-      private int bitField0_;
-
-      private org.sonarqube.ws.Permissions.PermissionTemplate permissionTemplate_ = org.sonarqube.ws.Permissions.PermissionTemplate.getDefaultInstance();
-      private com.google.protobuf.SingleFieldBuilder<
-          org.sonarqube.ws.Permissions.PermissionTemplate, org.sonarqube.ws.Permissions.PermissionTemplate.Builder, org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder> permissionTemplateBuilder_;
       /**
-       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
        */
-      public boolean hasPermissionTemplate() {
-        return ((bitField0_ & 0x00000001) == 0x00000001);
+      public Builder addPermissions(
+          int index, org.sonarqube.ws.Permissions.Permission value) {
+        if (permissionsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensurePermissionsIsMutable();
+          permissions_.add(index, value);
+          onChanged();
+        } else {
+          permissionsBuilder_.addMessage(index, value);
+        }
+        return this;
       }
       /**
-       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
        */
-      public org.sonarqube.ws.Permissions.PermissionTemplate getPermissionTemplate() {
-        if (permissionTemplateBuilder_ == null) {
-          return permissionTemplate_;
+      public Builder addPermissions(
+          org.sonarqube.ws.Permissions.Permission.Builder builderForValue) {
+        if (permissionsBuilder_ == null) {
+          ensurePermissionsIsMutable();
+          permissions_.add(builderForValue.build());
+          onChanged();
         } else {
-          return permissionTemplateBuilder_.getMessage();
+          permissionsBuilder_.addMessage(builderForValue.build());
         }
+        return this;
       }
       /**
-       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
        */
-      public Builder setPermissionTemplate(org.sonarqube.ws.Permissions.PermissionTemplate value) {
-        if (permissionTemplateBuilder_ == null) {
-          if (value == null) {
-            throw new NullPointerException();
-          }
-          permissionTemplate_ = value;
+      public Builder addPermissions(
+          int index, org.sonarqube.ws.Permissions.Permission.Builder builderForValue) {
+        if (permissionsBuilder_ == null) {
+          ensurePermissionsIsMutable();
+          permissions_.add(index, builderForValue.build());
           onChanged();
         } else {
-          permissionTemplateBuilder_.setMessage(value);
+          permissionsBuilder_.addMessage(index, builderForValue.build());
         }
-        bitField0_ |= 0x00000001;
         return this;
       }
       /**
-       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
        */
-      public Builder setPermissionTemplate(
-          org.sonarqube.ws.Permissions.PermissionTemplate.Builder builderForValue) {
-        if (permissionTemplateBuilder_ == null) {
-          permissionTemplate_ = builderForValue.build();
+      public Builder addAllPermissions(
+          java.lang.Iterable<? extends org.sonarqube.ws.Permissions.Permission> values) {
+        if (permissionsBuilder_ == null) {
+          ensurePermissionsIsMutable();
+          com.google.protobuf.AbstractMessageLite.Builder.addAll(
+              values, permissions_);
           onChanged();
         } else {
-          permissionTemplateBuilder_.setMessage(builderForValue.build());
+          permissionsBuilder_.addAllMessages(values);
         }
-        bitField0_ |= 0x00000001;
         return this;
       }
       /**
-       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
        */
-      public Builder mergePermissionTemplate(org.sonarqube.ws.Permissions.PermissionTemplate value) {
-        if (permissionTemplateBuilder_ == null) {
-          if (((bitField0_ & 0x00000001) == 0x00000001) &&
-              permissionTemplate_ != org.sonarqube.ws.Permissions.PermissionTemplate.getDefaultInstance()) {
-            permissionTemplate_ =
-              org.sonarqube.ws.Permissions.PermissionTemplate.newBuilder(permissionTemplate_).mergeFrom(value).buildPartial();
-          } else {
-            permissionTemplate_ = value;
-          }
+      public Builder clearPermissions() {
+        if (permissionsBuilder_ == null) {
+          permissions_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000002);
           onChanged();
         } else {
-          permissionTemplateBuilder_.mergeFrom(value);
+          permissionsBuilder_.clear();
         }
-        bitField0_ |= 0x00000001;
         return this;
       }
       /**
-       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
        */
-      public Builder clearPermissionTemplate() {
-        if (permissionTemplateBuilder_ == null) {
-          permissionTemplate_ = org.sonarqube.ws.Permissions.PermissionTemplate.getDefaultInstance();
+      public Builder removePermissions(int index) {
+        if (permissionsBuilder_ == null) {
+          ensurePermissionsIsMutable();
+          permissions_.remove(index);
           onChanged();
         } else {
-          permissionTemplateBuilder_.clear();
+          permissionsBuilder_.remove(index);
         }
-        bitField0_ = (bitField0_ & ~0x00000001);
         return this;
       }
       /**
-       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
        */
-      public org.sonarqube.ws.Permissions.PermissionTemplate.Builder getPermissionTemplateBuilder() {
-        bitField0_ |= 0x00000001;
-        onChanged();
-        return getPermissionTemplateFieldBuilder().getBuilder();
+      public org.sonarqube.ws.Permissions.Permission.Builder getPermissionsBuilder(
+          int index) {
+        return getPermissionsFieldBuilder().getBuilder(index);
       }
       /**
-       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
        */
-      public org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder getPermissionTemplateOrBuilder() {
-        if (permissionTemplateBuilder_ != null) {
-          return permissionTemplateBuilder_.getMessageOrBuilder();
+      public org.sonarqube.ws.Permissions.PermissionOrBuilder getPermissionsOrBuilder(
+          int index) {
+        if (permissionsBuilder_ == null) {
+          return permissions_.get(index);  } else {
+          return permissionsBuilder_.getMessageOrBuilder(index);
+        }
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+       */
+      public java.util.List<? extends org.sonarqube.ws.Permissions.PermissionOrBuilder> 
+           getPermissionsOrBuilderList() {
+        if (permissionsBuilder_ != null) {
+          return permissionsBuilder_.getMessageOrBuilderList();
         } else {
-          return permissionTemplate_;
+          return java.util.Collections.unmodifiableList(permissions_);
         }
       }
       /**
-       * <code>optional .sonarqube.ws.permissions.PermissionTemplate permissionTemplate = 1;</code>
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
        */
-      private com.google.protobuf.SingleFieldBuilder<
-          org.sonarqube.ws.Permissions.PermissionTemplate, org.sonarqube.ws.Permissions.PermissionTemplate.Builder, org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder> 
-          getPermissionTemplateFieldBuilder() {
-        if (permissionTemplateBuilder_ == null) {
-          permissionTemplateBuilder_ = new com.google.protobuf.SingleFieldBuilder<
-              org.sonarqube.ws.Permissions.PermissionTemplate, org.sonarqube.ws.Permissions.PermissionTemplate.Builder, org.sonarqube.ws.Permissions.PermissionTemplateOrBuilder>(
-                  getPermissionTemplate(),
+      public org.sonarqube.ws.Permissions.Permission.Builder addPermissionsBuilder() {
+        return getPermissionsFieldBuilder().addBuilder(
+            org.sonarqube.ws.Permissions.Permission.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+       */
+      public org.sonarqube.ws.Permissions.Permission.Builder addPermissionsBuilder(
+          int index) {
+        return getPermissionsFieldBuilder().addBuilder(
+            index, org.sonarqube.ws.Permissions.Permission.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .sonarqube.ws.permissions.Permission permissions = 3;</code>
+       */
+      public java.util.List<org.sonarqube.ws.Permissions.Permission.Builder> 
+           getPermissionsBuilderList() {
+        return getPermissionsFieldBuilder().getBuilderList();
+      }
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonarqube.ws.Permissions.Permission, org.sonarqube.ws.Permissions.Permission.Builder, org.sonarqube.ws.Permissions.PermissionOrBuilder> 
+          getPermissionsFieldBuilder() {
+        if (permissionsBuilder_ == null) {
+          permissionsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
+              org.sonarqube.ws.Permissions.Permission, org.sonarqube.ws.Permissions.Permission.Builder, org.sonarqube.ws.Permissions.PermissionOrBuilder>(
+                  permissions_,
+                  ((bitField0_ & 0x00000002) == 0x00000002),
                   getParentForChildren(),
                   isClean());
-          permissionTemplate_ = null;
+          permissions_ = null;
         }
-        return permissionTemplateBuilder_;
+        return permissionsBuilder_;
       }
 
-      // @@protoc_insertion_point(builder_scope:sonarqube.ws.permissions.UpdatePermissionTemplateResponse)
+      // @@protoc_insertion_point(builder_scope:sonarqube.ws.permissions.SearchTemplatesResponse)
     }
 
     static {
-      defaultInstance = new UpdatePermissionTemplateResponse(true);
+      defaultInstance = new SearchTemplatesResponse(true);
       defaultInstance.initFields();
     }
 
-    // @@protoc_insertion_point(class_scope:sonarqube.ws.permissions.UpdatePermissionTemplateResponse)
+    // @@protoc_insertion_point(class_scope:sonarqube.ws.permissions.SearchTemplatesResponse)
   }
 
   private static final com.google.protobuf.Descriptors.Descriptor
@@ -10081,6 +11555,11 @@ public final class Permissions {
   private static
     com.google.protobuf.GeneratedMessage.FieldAccessorTable
       internal_static_sonarqube_ws_permissions_UpdatePermissionTemplateResponse_fieldAccessorTable;
+  private static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_sonarqube_ws_permissions_SearchTemplatesResponse_descriptor;
+  private static
+    com.google.protobuf.GeneratedMessage.FieldAccessorTable
+      internal_static_sonarqube_ws_permissions_SearchTemplatesResponse_fieldAccessorTable;
 
   public static com.google.protobuf.Descriptors.FileDescriptor
       getDescriptor() {
@@ -10115,17 +11594,23 @@ public final class Permissions {
       "ermission\032~\n\007Project\022\n\n\002id\030\001 \001(\t\022\013\n\003key\030" +
       "\002 \001(\t\022\021\n\tqualifier\030\003 \001(\t\022\014\n\004name\030\004 \001(\t\0229" +
       "\n\013permissions\030\005 \003(\0132$.sonarqube.ws.permi" +
-      "ssions.Permission\"\204\001\n\022PermissionTemplate" +
+      "ssions.Permission\"\342\001\n\022PermissionTemplate" +
       "\022\n\n\002id\030\001 \001(\t\022\014\n\004name\030\002 \001(\t\022\023\n\013descriptio" +
       "n\030\003 \001(\t\022\031\n\021projectKeyPattern\030\004 \001(\t\022\021\n\tcr" +
-      "eatedAt\030\005 \001(\t\022\021\n\tupdatedAt\030\006 \001(\t\"l\n Crea" +
-      "tePermissionTemplateResponse\022H\n\022permissi",
-      "onTemplate\030\001 \001(\0132,.sonarqube.ws.permissi" +
-      "ons.PermissionTemplate\"l\n UpdatePermissi" +
-      "onTemplateResponse\022H\n\022permissionTemplate" +
-      "\030\001 \001(\0132,.sonarqube.ws.permissions.Permis" +
-      "sionTemplateB!\n\020org.sonarqube.wsB\013Permis" +
-      "sionsH\001"
+      "eatedAt\030\005 \001(\t\022\021\n\tupdatedAt\030\006 \001(\t\022!\n\031perm" +
+      "issionsPresentIfEmpty\030\007 \001(\010\0229\n\013permissio",
+      "ns\030\010 \003(\0132$.sonarqube.ws.permissions.Perm" +
+      "ission\"l\n CreatePermissionTemplateRespon" +
+      "se\022H\n\022permissionTemplate\030\001 \001(\0132,.sonarqu" +
+      "be.ws.permissions.PermissionTemplate\"l\n " +
+      "UpdatePermissionTemplateResponse\022H\n\022perm" +
+      "issionTemplate\030\001 \001(\0132,.sonarqube.ws.perm" +
+      "issions.PermissionTemplate\"\237\001\n\027SearchTem" +
+      "platesResponse\022I\n\023permissionTemplates\030\002 " +
+      "\003(\0132,.sonarqube.ws.permissions.Permissio" +
+      "nTemplate\0229\n\013permissions\030\003 \003(\0132$.sonarqu",
+      "be.ws.permissions.PermissionB!\n\020org.sona" +
+      "rqube.wsB\013PermissionsH\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
         new com.google.protobuf.Descriptors.FileDescriptor.    InternalDescriptorAssigner() {
@@ -10193,7 +11678,7 @@ public final class Permissions {
     internal_static_sonarqube_ws_permissions_PermissionTemplate_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_sonarqube_ws_permissions_PermissionTemplate_descriptor,
-        new java.lang.String[] { "Id", "Name", "Description", "ProjectKeyPattern", "CreatedAt", "UpdatedAt", });
+        new java.lang.String[] { "Id", "Name", "Description", "ProjectKeyPattern", "CreatedAt", "UpdatedAt", "PermissionsPresentIfEmpty", "Permissions", });
     internal_static_sonarqube_ws_permissions_CreatePermissionTemplateResponse_descriptor =
       getDescriptor().getMessageTypes().get(6);
     internal_static_sonarqube_ws_permissions_CreatePermissionTemplateResponse_fieldAccessorTable = new
@@ -10206,6 +11691,12 @@ public final class Permissions {
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_sonarqube_ws_permissions_UpdatePermissionTemplateResponse_descriptor,
         new java.lang.String[] { "PermissionTemplate", });
+    internal_static_sonarqube_ws_permissions_SearchTemplatesResponse_descriptor =
+      getDescriptor().getMessageTypes().get(8);
+    internal_static_sonarqube_ws_permissions_SearchTemplatesResponse_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+        internal_static_sonarqube_ws_permissions_SearchTemplatesResponse_descriptor,
+        new java.lang.String[] { "PermissionTemplates", "Permissions", });
     org.sonarqube.ws.Common.getDescriptor();
   }
 
index aa7cfae1c59ef6bd0dcd8dda6130bda522e2726b..72ee5ee1440dd22413e8c55c78a27487728dcd88 100644 (file)
@@ -91,6 +91,8 @@ message PermissionTemplate {
   optional string createdAt = 5;
   // ex: 2015-08-25T16:18:48+0200
   optional string updatedAt = 6;
+  optional bool permissionsPresentIfEmpty = 7;
+  repeated Permission permissions = 8;
 }
 
 message CreatePermissionTemplateResponse {
@@ -100,3 +102,8 @@ message CreatePermissionTemplateResponse {
 message UpdatePermissionTemplateResponse {
   optional PermissionTemplate permissionTemplate = 1;
 }
+
+message SearchTemplatesResponse {
+  repeated PermissionTemplate permissionTemplates = 2;
+  repeated Permission permissions = 3;
+}