From a441a1665bc8dd78b70cc842ad9777ff0ec6daee Mon Sep 17 00:00:00 2001
From: zj <1772600164@qq.com>
Date: Sat, 23 Aug 2025 02:11:45 +0800
Subject: [PATCH] 1

---
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/BasicSetupController.java |   51 +++++++++++-
 ruoyi-admin/src/main/java/com/ruoyi/im/config/AddTeamMembersRequest.java            |    2 
 ruoyi-admin/src/main/java/com/ruoyi/im/service/NeteaseTeamService.java              |    2 
 ruoyi-admin/src/main/java/com/ruoyi/im/ImApiController.java                         |    4 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/group/ImGroupController.java     |  114 ++++++++++++++++++++++++++--
 ruoyi-admin/src/main/java/com/ruoyi/im/config/CreateTeamRequest.java                |    1 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java        |    1 
 ruoyi-admin/src/main/java/com/ruoyi/im/out/UserAccountOut.java                      |    2 
 ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/NeteaseTeamServiceImpl.java     |   38 ++++++---
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/user/UserController.java         |    3 
 10 files changed, 184 insertions(+), 34 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/im/ImApiController.java b/ruoyi-admin/src/main/java/com/ruoyi/im/ImApiController.java
index 6fb0d5a..efe7b9f 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/im/ImApiController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/im/ImApiController.java
@@ -62,7 +62,7 @@
 
 
     /**
-     * 获取参数配置列表
+     * 注册
      */
     @PostMapping("/register")
     public Result register(@Validated RegisterDto dto){
@@ -78,7 +78,7 @@
      * 获取ip地址并判断是否在黑名单
      */
     @GetMapping("/blacklist")
-    public Result blacklist(HttpServletRequest request,@PathVariable("account") String account){
+    public Result blacklist(HttpServletRequest request,@RequestParam("account") String account){
         try {
             String clientIp = IpUtils.getClientIp(request);
             if(StringUtils.isEmpty(clientIp)){
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/im/config/AddTeamMembersRequest.java b/ruoyi-admin/src/main/java/com/ruoyi/im/config/AddTeamMembersRequest.java
index 41b2668..f8d0db6 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/im/config/AddTeamMembersRequest.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/im/config/AddTeamMembersRequest.java
@@ -21,6 +21,8 @@
 
         private String groupId;//群id
 
+        private Integer number;//拉人数量 拉人为自动拉虚拟注册的用户;如果填写了云信账号数量无效(最大支持99人)
+
         /**
          * 邀请入群的成员账号ID列表,必填
          */
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/im/config/CreateTeamRequest.java b/ruoyi-admin/src/main/java/com/ruoyi/im/config/CreateTeamRequest.java
index 77fe78f..dd5cb1e 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/im/config/CreateTeamRequest.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/im/config/CreateTeamRequest.java
@@ -10,7 +10,6 @@
 @Data
 public class CreateTeamRequest {
 
-    @NotBlank(message = "群主id为空")
     private String groupId;
 
 
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/im/out/UserAccountOut.java b/ruoyi-admin/src/main/java/com/ruoyi/im/out/UserAccountOut.java
index a1c6bcc..412cf1a 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/im/out/UserAccountOut.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/im/out/UserAccountOut.java
@@ -13,6 +13,8 @@
 @Data
 public class UserAccountOut {
 
+    private Integer id;
+
     // 账号(唯一)
     private String account;
 
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/im/service/NeteaseTeamService.java b/ruoyi-admin/src/main/java/com/ruoyi/im/service/NeteaseTeamService.java
index 4a677e6..3a9add9 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/im/service/NeteaseTeamService.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/im/service/NeteaseTeamService.java
@@ -18,5 +18,5 @@
 
     AjaxResult assignment(AssignmentRequest request);
 
-    AjaxResult dismiss(Long id);
+    AjaxResult dismiss(Integer id);
 }
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/NeteaseTeamServiceImpl.java b/ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/NeteaseTeamServiceImpl.java
index 2fb1eb6..d859cab 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/NeteaseTeamServiceImpl.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/NeteaseTeamServiceImpl.java
@@ -4,7 +4,9 @@
 import com.alibaba.druid.support.json.JSONUtils;
 import com.alibaba.fastjson2.JSON;
 import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.netease.nim.server.sdk.core.YunxinApiHttpClient;
 import com.netease.nim.server.sdk.core.YunxinApiResponse;
 import com.netease.nim.server.sdk.core.exception.YunxinSdkException;
@@ -17,8 +19,10 @@
 import com.ruoyi.im.config.CreateTeamRequest;
 import com.ruoyi.im.config.AssignmentRequest;
 import com.ruoyi.im.service.NeteaseTeamService;
+import com.ruoyi.system.domain.GroupWelcomeConfig;
 import com.ruoyi.system.domain.NeteaseTeam;
 import com.ruoyi.system.mapper.NeteaseTeamMapper;
+import com.ruoyi.system.service.GroupWelcomeConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -39,7 +43,8 @@
         this.yunxinClient = yunxinClient;
     }
 
-
+    @Autowired
+    GroupWelcomeConfigService groupWelcomeConfigService;
 
     @Resource
     private NeteaseTeamMapper neteaseTeamMapper;
@@ -114,7 +119,7 @@
             String jsonBody = JSON.toJSONString(paramMap);
 
             NeteaseTeam neteaseTeam = neteaseTeamMapper.selectById(request.getGroupId());
-            if(ObjectUtil.isNotEmpty(neteaseTeam)){
+            if(ObjectUtil.isEmpty(neteaseTeam)){
                 return AjaxResult.error("群不存在!");
             }
 
@@ -258,18 +263,23 @@
         try {
 
             NeteaseTeam neteaseTeam = neteaseTeamMapper.selectById(request.getGroupId());
-            if(ObjectUtil.isNotEmpty(neteaseTeam)){
+            if(ObjectUtil.isEmpty(neteaseTeam)){
                 return AjaxResult.error("群不存在!");
             }
+            GroupWelcomeConfig groupWelcomeConfig = groupWelcomeConfigService.getOne(new LambdaQueryWrapper<>(GroupWelcomeConfig.class)
+                    .eq(GroupWelcomeConfig::getConfigurationName, "IM-BASICS").last(" limit 1"));
 
             AddTeamMembersRequest build = AddTeamMembersRequest.builder()
                     .inviteAccountIds(request.getInviteAccountIds())
-                    .operatorId(request.getOperatorId())
+                    .operatorId(groupWelcomeConfig.getUserAccid())
                     .msg(request.getMsg())
-                    .teamId(Long.getLong(neteaseTeam.getTid()))
+                    .teamId(Long.valueOf(neteaseTeam.getTid()))
                     .teamType(neteaseTeam.getTeamType())
                     .build();
-            String jsonBody = JSONUtils.toJSONString(build);
+
+// 方法1:使用 Jackson ObjectMapper
+            ObjectMapper objectMapper = new ObjectMapper();
+            String jsonBody = objectMapper.writeValueAsString(build);
 
             YunxinApiResponse response = yunxinClient.executeV2Api(
                     HttpMethod.POST,
@@ -307,16 +317,18 @@
         try {
 
             NeteaseTeam neteaseTeam = neteaseTeamMapper.selectById(request.getGroupId());
-            if(ObjectUtil.isNotEmpty(neteaseTeam)){
+            if(ObjectUtil.isEmpty(neteaseTeam)){
                 return AjaxResult.error("群不存在!");
             }
 
             AssignmentRequest build = AssignmentRequest.builder()
-                    .teamId(Long.getLong(neteaseTeam.getTid()))
+                    .teamId(Long.valueOf(neteaseTeam.getTid()))
                     .team_type(neteaseTeam.getTeamType())
-                    .leave(2)
+                    .new_owner_account_id(request.getNew_owner_account_id())
+                    .leave(request.getLeave())
                     .build();
-            String requestBody = JSONUtils.toJSONString(build);
+            ObjectMapper objectMapper = new ObjectMapper();
+            String requestBody = objectMapper.writeValueAsString(build);
 
             String path = TeamV2UrlContext.TRANSFER_OWNER.replace("{team_id}",neteaseTeam.getTid().toString());
 
@@ -352,10 +364,10 @@
     }
 
     @Override
-    public AjaxResult dismiss(Long id) {
+    public AjaxResult dismiss(Integer id) {
         try {
             NeteaseTeam neteaseTeam = neteaseTeamMapper.selectById(id);
-            if(ObjectUtil.isNotEmpty(neteaseTeam)){
+            if(ObjectUtil.isEmpty(neteaseTeam)){
                 return AjaxResult.error("群不存在!");
             }
             Map<String, String> queryParams = new HashMap<>();
@@ -380,6 +392,8 @@
                 log.error("网易云信解散群失败,响应:");
                 return AjaxResult.error("解散群失败");
             }
+            neteaseTeam.setStatus(1);
+            neteaseTeamMapper.updateById(neteaseTeam);
             return AjaxResult.success();
         } catch (YunxinSdkException e) {
             // 云信调用异常时回滚事务
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/group/ImGroupController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/group/ImGroupController.java
index 9010da3..26dd46f 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/group/ImGroupController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/group/ImGroupController.java
@@ -5,20 +5,34 @@
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.im.comm.Result;
 import com.ruoyi.im.config.AddTeamMembersRequest;
 import com.ruoyi.im.config.CreateTeamRequest;
 import com.ruoyi.im.config.AssignmentRequest;
+import com.ruoyi.im.dto.UpdateUserBusinessDto;
 import com.ruoyi.im.service.NeteaseTeamService;
 import com.ruoyi.system.domain.NeteaseTeam;
 import com.ruoyi.system.domain.UserAccount;
 import com.ruoyi.system.domain.vo.UserAccountVo;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
 
 @RestController
 @RequestMapping("/im/group")
@@ -29,12 +43,18 @@
     @Autowired
     NeteaseTeamService neteaseGroupService;
 
+    @Value("${file.upload-dir}")
+    private String uploadDir;
+
+    @Value("${file.upload-prefix}")
+    private String prefix;
+
     /**
-     * 获取会员列表
+     * 获取群组列表
      */
-    @PreAuthorize("@ss.hasPermi('im:group:list')")
+//    @PreAuthorize("@ss.hasPermi('im:group:list')")
     @GetMapping("/list")
-    public TableDataInfo list(@PathVariable("keyword") String keyword)
+    public TableDataInfo list(@PathVariable(value = "keyword", required = false) String keyword)
     {
         // 创建查询条件包装器
         LambdaQueryWrapper<NeteaseTeam> queryWrapper = new LambdaQueryWrapper<>();
@@ -52,6 +72,7 @@
 
         // 默认按创建时间倒序
         queryWrapper.orderByDesc(NeteaseTeam::getCreateTime);
+        startPage();
         List<NeteaseTeam> list = neteaseGroupService.list(queryWrapper);
         return getDataTable(list);
     }
@@ -61,7 +82,7 @@
      * 创建群组
      */
     @PostMapping("/create")
-    public AjaxResult createGroup(@Validated @RequestBody CreateTeamRequest request) {
+    public AjaxResult createGroup(CreateTeamRequest request) {
         return neteaseGroupService.createGroup(request);
     }
 
@@ -69,7 +90,7 @@
      * 更新群组
      */
     @PostMapping("/updateCreate")
-    public AjaxResult updateCreate(@Validated @RequestBody CreateTeamRequest request) {
+    public AjaxResult updateCreate(CreateTeamRequest request) {
         return neteaseGroupService.updateCreate(request);
     }
 
@@ -77,7 +98,7 @@
      * 拉人进去
      */
     @PostMapping("/inviteTeamMembers")
-    public AjaxResult inviteTeamMembers(@Validated @RequestBody AddTeamMembersRequest request) {
+    public AjaxResult inviteTeamMembers( AddTeamMembersRequest request) {
         return neteaseGroupService.inviteTeamMembers(request);
     }
 
@@ -85,16 +106,89 @@
      * 转让群主
      */
     @PostMapping("/assignment")
-    public AjaxResult assignment(@Validated @RequestBody AssignmentRequest request) {
+    public AjaxResult assignment(AssignmentRequest request) {
         return neteaseGroupService.assignment(request);
     }
 
     /**
      * 解散
      */
-    @PostMapping("/dismiss")
-    public AjaxResult dismiss(@PathVariable("id") Long id) {
-        return neteaseGroupService.dismiss(id);
+    @GetMapping("/dismiss")
+    public AjaxResult dismiss(@RequestParam(value = "groupId") Integer groupId) {
+        return neteaseGroupService.dismiss(groupId);
     }
 
+
+    @PostMapping("/upload")
+    public Result uploadFile(@RequestParam("file") MultipartFile file) {
+        try {
+
+            // 1. 验证文件类型
+            String contentType = file.getContentType();
+            if (contentType == null ||
+                    (!contentType.equals("image/jpeg") &&
+                            !contentType.equals("image/png") &&
+                            !contentType.equals("image/gif"))) {
+
+                return Result.error("只支持JPEG、PNG和GIF格式的图片!");
+            }
+
+            // 确保上传目录存在
+            File directory = new File(uploadDir);
+            if (!directory.exists()) {
+                directory.mkdirs();
+                // 设置目录权限为755 (rwxr-xr-x)
+                setPermissions(directory, "rwxr-xr-x");
+            }
+
+            // 生成唯一文件名
+            String fileName = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
+            Path filePath = Paths.get(uploadDir, fileName);
+
+            // 保存文件
+            Files.write(filePath, file.getBytes());
+
+            // 设置文件权限为644 (rw-r--r--)
+            setPermissions(filePath.toFile(), "rw-r--r--");
+
+            // 5. 调用网易云信API更新头像
+            fileName = prefix+"/"+fileName;
+            return Result.success("文件上传成功",fileName);
+        } catch (IOException e) {
+            return Result.error("文件上传失败");
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error("设置文件权限失败!");
+        }
+        return Result.success();
+    }
+
+    /**
+     * 设置文件/目录权限
+     * @param file 文件或目录对象
+     * @param perm 权限字符串,如 "rw-r--r--"
+     */
+    private void setPermissions(File file, String perm) throws IOException {
+        // 获取当前操作系统
+        String os = System.getProperty("os.name").toLowerCase();
+
+        // 只有在Unix/Linux系统上才能设置POSIX权限
+        if (os.contains("nix") || os.contains("nux") || os.contains("mac")) {
+            Set<PosixFilePermission> permissions = PosixFilePermissions.fromString(perm);
+            Files.setPosixFilePermissions(file.toPath(), permissions);
+        } else {
+            // Windows系统不支持POSIX权限,可以设置基本权限
+            file.setReadable(true, false);    // 所有用户可读
+            if (perm.startsWith("rw")) {
+                file.setWritable(true, false); // 所有用户可写(如果权限字符串以rw开头)
+            } else {
+                file.setWritable(false, false);
+            }
+
+            // 如果是目录且包含执行权限,设置可执行
+            if (file.isDirectory() && perm.contains("x")) {
+                file.setExecutable(true, false);
+            }
+        }
+    }
 }
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/BasicSetupController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/BasicSetupController.java
index 2e0b91b..b0dd8a5 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/BasicSetupController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/BasicSetupController.java
@@ -2,10 +2,13 @@
 
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.im.config.CreateTeamRequest;
 import com.ruoyi.system.domain.GroupWelcomeConfig;
 import com.ruoyi.system.domain.IpBlacklist;
+import com.ruoyi.system.domain.NeteaseTeam;
 import com.ruoyi.system.service.GroupWelcomeConfigService;
 import com.ruoyi.system.service.IpBlacklistService;
 import org.aspectj.weaver.loadtime.Aj;
@@ -23,7 +26,7 @@
  **/
 @RestController
 @RequestMapping("/system/basic")
-public class BasicSetupController {
+public class BasicSetupController extends BaseController {
 
     @Autowired
     GroupWelcomeConfigService groupWelcomeConfigService;
@@ -33,10 +36,10 @@
 
 
     /**
-     * 创建群组
+     * 修改基础信息
      */
     @PostMapping("/update")
-    public AjaxResult createGroup(@Validated @RequestBody GroupWelcomeConfig vo) {
+    public AjaxResult update(GroupWelcomeConfig vo) {
         GroupWelcomeConfig configServiceById = groupWelcomeConfigService.getById(vo.getId());
         if(ObjectUtil.isEmpty(configServiceById)){
             return AjaxResult.error("请联系管理员初始化配置");
@@ -53,10 +56,44 @@
     }
 
     /**
+     * 查询基础信息
+     */
+    @GetMapping("/get")
+    public AjaxResult get() {
+        GroupWelcomeConfig groupWelcomeConfig = groupWelcomeConfigService.getOne(new LambdaQueryWrapper<>(GroupWelcomeConfig.class)
+                .eq(GroupWelcomeConfig::getConfigurationName, "IM-BASICS").last(" limit 1"));
+        return AjaxResult.success(groupWelcomeConfig);
+    }
+
+    /**
+     * ip黑名单列表
+     */
+//    @PreAuthorize("@ss.hasPermi('im:group:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(@RequestParam(value = "keyword", required = false) String keyword)
+    {
+        // 创建查询条件包装器
+        LambdaQueryWrapper<IpBlacklist> queryWrapper = new LambdaQueryWrapper<>();
+
+        // 只有当 keyword 不为空时才添加 OR 条件
+        if (ObjectUtil.isNotEmpty(keyword)) {
+            queryWrapper.and(wrapper -> wrapper.eq(IpBlacklist::getIpAddress,keyword)
+            );
+        }
+
+        // 默认按创建时间倒序
+        queryWrapper.orderByDesc(IpBlacklist::getCreateTime);
+        startPage();
+        List<IpBlacklist> list = ipBlacklistService.list(queryWrapper);
+        return getDataTable(list);
+    }
+
+
+    /**
      * 新增ip黑名单
      */
     @PostMapping("/addIp")
-    public AjaxResult addIp(@PathVariable("ip") String ip) {
+    public AjaxResult addIp(@RequestParam("ip") String ip) {
 
         long count = ipBlacklistService.count(new LambdaQueryWrapper<>(IpBlacklist.class).eq(IpBlacklist::getIpAddress, ip));
         if(count > 0){
@@ -70,17 +107,17 @@
     }
 
     /**
-     * 新增ip黑名单
+     * 删除ip黑名单
      */
     @PostMapping("/deleteIp")
-    public AjaxResult addIp(@PathVariable("id") Integer id) {
+    public AjaxResult addIp(@RequestParam("id") Integer id) {
 
         IpBlacklist ipBlacklist = ipBlacklistService.getById(id);
         if(ObjectUtil.isEmpty(ipBlacklist)){
             return AjaxResult.error("ip地址不存在!");
         }
         ipBlacklistService.removeById(id);
-        return AjaxResult.success("添加成功");
+        return AjaxResult.success("删除成功");
     }
 
 }
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/user/UserController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/user/UserController.java
index 7a37853..5743639 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/user/UserController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/user/UserController.java
@@ -43,7 +43,7 @@
     /**
      * 获取会员列表
      */
-    @PreAuthorize("@ss.hasPermi('im:user:list')")
+//    @PreAuthorize("@ss.hasPermi('im:user:list')")
     @GetMapping("/list")
     public TableDataInfo list(UserAccountVo vo)
     {
@@ -73,6 +73,7 @@
 
         // 默认按创建时间倒序
         queryWrapper.orderByDesc(UserAccount::getCreateTime);
+        startPage();
         List<UserAccount> list = userAccountService.list(queryWrapper);
         List<UserAccountOut> toList = ConverterUtil.convertToList(list, UserAccountOut.class);
         return getDataTable(toList);
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
index d27572d..ff362ec 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
@@ -118,6 +118,7 @@
                     .antMatchers("/im/api/**").permitAll()
                     .antMatchers("/im/user/**").permitAll()
                     .antMatchers("/im/group/**").permitAll()
+                    .antMatchers("/system/basic/**").permitAll()
                     // 除上面外的所有请求全部需要鉴权认证
                     .anyRequest().authenticated();
             })

--
Gitblit v1.9.3