From 9486766c806fe1d9e082b2fd02ea1cc558f1b443 Mon Sep 17 00:00:00 2001 From: 无关风月 <443237572@qq.com> Date: 星期四, 08 五月 2025 09:21:57 +0800 Subject: [PATCH] bug修改 --- cloud-server-account/src/main/java/com/dsh/account/controller/UseBenefitsController.java | 412 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 365 insertions(+), 47 deletions(-) diff --git a/cloud-server-account/src/main/java/com/dsh/account/controller/UseBenefitsController.java b/cloud-server-account/src/main/java/com/dsh/account/controller/UseBenefitsController.java index 2b9f225..499eada 100644 --- a/cloud-server-account/src/main/java/com/dsh/account/controller/UseBenefitsController.java +++ b/cloud-server-account/src/main/java/com/dsh/account/controller/UseBenefitsController.java @@ -2,24 +2,30 @@ import com.dsh.account.entity.TAppUser; +import com.dsh.account.feignclient.activity.model.IntegralCommodity; import com.dsh.account.feignclient.other.SysLogClient; import com.dsh.account.model.vo.userBenefitDetail.*; import com.dsh.account.service.RechargeRecordsService; import com.dsh.account.service.TAppUserService; +import com.dsh.account.service.UserIntegralChangesService; +import com.dsh.account.util.PayMoneyUtil; import com.dsh.account.util.ResultUtil; import com.dsh.account.util.TokenUtil; +import com.dsh.account.util.ToolUtil; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.List; +import java.util.Map; /** * 使用福利 控制器 @@ -42,23 +48,38 @@ @Autowired private RechargeRecordsService rechargeRService; + @Autowired + private UserIntegralChangesService uicService; + private final SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd"); + + @Autowired + private PayMoneyUtil payMoneyUtil; @ResponseBody @PostMapping("/api/useBenefit/indexOfAppUser") - @ApiOperation(value = "福利主页", tags = {"APP-使用福利"}) + @ApiOperation(value = "福利主页【2.0】", tags = {"APP-使用福利"}) @ApiImplicitParams({ @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), + @ApiImplicitParam(name = "lat", value = "经度", dataType = "string"), + @ApiImplicitParam(name = "lon", value = "纬度", dataType = "string") }) - public ResultUtil<IndexOfUserBenefirVo> queryAppUserUser(){ + public ResultUtil<IndexOfUserBenefirVo> queryAppUserUser(String lon, String lat) { try { Integer appUserId = tokenUtil.getUserIdFormRedis(); - if(null == appUserId){ + if (null == appUserId) { return ResultUtil.tokenErr(); } - return ResultUtil.success(tauService.queryBenefitDetails(appUserId)); - }catch (Exception e){ + IndexOfUserBenefirVo indexOfUserBenefirVo = tauService.queryBenefitDetails(appUserId, lon, lat); + List<IntegralCommodity> commodities = indexOfUserBenefirVo.getCommodities(); + if (commodities.size() > 5) { + commodities = commodities.subList(0, 5); + } + indexOfUserBenefirVo.setCommodities(commodities); + return ResultUtil.success(indexOfUserBenefirVo); + } catch (Exception e) { + e.printStackTrace(); return ResultUtil.runErr(); } } @@ -69,30 +90,83 @@ @ApiOperation(value = "用户个人信息", tags = {"APP-使用福利"}) @ApiImplicitParams({ @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), + @ApiImplicitParam(name = "lat", value = "经度", dataType = "string"), + @ApiImplicitParam(name = "lon", value = "纬度", dataType = "string") + }) - public ResultUtil<AppUserDetailsVo> queryAppUserDetails(){ + public ResultUtil<AppUserDetailsVo> queryAppUserDetails() { try { AppUserDetailsVo detailsVo = new AppUserDetailsVo(); Integer appUserId = tokenUtil.getUserIdFormRedis(); - if(null == appUserId){ + if (null == appUserId) { return ResultUtil.tokenErr(); } TAppUser tAppUser = tauService.getBaseMapper().selectById(appUserId); - if (null != tAppUser){ - detailsVo.setUserImage(tAppUser.getHeadImg()); + if (tAppUser.getCode() == null) { + detailsVo.setNeedChange(1); + } else { + detailsVo.setNeedChange(0); + } + + + if (null != tAppUser) { + detailsVo.setUserId(appUserId); + if (tAppUser.getHeadImg() != null) { + detailsVo.setUserImage(tAppUser.getHeadImg()); + } else { + detailsVo.setUserImage("https://we-park-life.oss-cn-beijing.aliyuncs.com/img/630864764d3c4e98822ff976a2389559.jpg"); + } + + detailsVo.setUserName(tAppUser.getName()); detailsVo.setUserPhone(tAppUser.getPhone()); - detailsVo.setSex(tAppUser.getGender() == 1 ? "男" : "女"); - detailsVo.setBirthday(format1.format(tAppUser.getBirthday())); - detailsVo.setAddress(tAppUser.getProvince()+tAppUser.getCity()); - detailsVo.setMemberLifespan(format1.format(tAppUser.getVipEndTime())); + detailsVo.setIsVip(tAppUser.getIsVip()); + if (tAppUser.getGender() != null) { + detailsVo.setSex(tAppUser.getGender() == 1 ? "男" : "女"); + } + System.out.println("=============" + tAppUser); + + if (tAppUser.getBirthday() != null) { + detailsVo.setBirthday(format1.format(tAppUser.getBirthday())); + } + detailsVo.setAddress(tAppUser.getProvince() + tAppUser.getCity()); + if (tAppUser.getVipEndTime() != null) { + + detailsVo.setMemberLifespan(format1.format(tAppUser.getVipEndTime())); + } } return ResultUtil.success(detailsVo); - }catch (Exception e){ + } catch (Exception e) { return ResultUtil.runErr(); } } + + @ResponseBody + @PostMapping("/api/useBenefit/uploadImage") + @ApiOperation(value = "上传用户头像", tags = {"APP-使用福利"}) + @ApiImplicitParams({ + @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), + @ApiImplicitParam(name = "userImage", value = "用户头像连接", dataType = "string") + }) + public ResultUtil uploadAppUserProfile(String userImage) { + try { + Integer appUserId = tokenUtil.getUserIdFormRedis(); + if (null == appUserId) { + return ResultUtil.tokenErr(); + } + TAppUser byId = tauService.getById(appUserId); + if (ToolUtil.isNotEmpty(userImage)) { + byId.setHeadImg(userImage); + tauService.updateById(byId); + } else { + ResultUtil.error("头像不能为空!"); + } + return ResultUtil.success(); + } catch (Exception e) { + return ResultUtil.runErr(); + } + } @ResponseBody @@ -101,10 +175,10 @@ @ApiImplicitParams({ @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), }) - public ResultUtil cancellationAccount(){ + public ResultUtil cancellationAccount() { try { Integer appUserId = tokenUtil.getUserIdFormRedis(); - if(null == appUserId){ + if (null == appUserId) { return ResultUtil.tokenErr(); } // 变更账号的状态为删除 @@ -114,11 +188,10 @@ // 删除redis中用户key tokenUtil.logout(); return ResultUtil.success(); - }catch (Exception e){ + } catch (Exception e) { return ResultUtil.runErr(); } } - @ResponseBody @@ -127,10 +200,10 @@ @ApiImplicitParams({ @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), }) - public ResultUtil logOutAccount(){ + public ResultUtil logOutAccount() { try { Integer appUserId = tokenUtil.getUserIdFormRedis(); - if(null == appUserId){ + if (null == appUserId) { return ResultUtil.tokenErr(); } // 增加一条退出账号的日志 @@ -138,11 +211,10 @@ // 删除redis中用户key tokenUtil.logout(); return ResultUtil.success(); - }catch (Exception e){ + } catch (Exception e) { return ResultUtil.runErr(); } } - @ResponseBody @@ -151,16 +223,16 @@ @ApiImplicitParams({ @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), @ApiImplicitParam(value = "年月", name = "yearMonth", required = true, dataType = "string"), - @ApiImplicitParam(value = "记录(1充值 2扣除)", name = "recordId", required = true, dataType = "int"), + @ApiImplicitParam(value = "记录(1充值 2扣除)", name = "recordId", required = false, dataType = "int"), }) - public ResultUtil<BillingDetailsVo> getUserBillingDetails(String yearMonth,Integer recordId){ + public ResultUtil<List<ConsumeDetail>> getUserBillingDetails(String yearMonth, Integer recordId) { try { Integer appUserId = tokenUtil.getUserIdFormRedis(); - if(null == appUserId){ + if (null == appUserId) { return ResultUtil.tokenErr(); } - return ResultUtil.success(tauService.queryUserBillingDetails(yearMonth,recordId,appUserId)); - }catch (Exception e){ + return ResultUtil.success(tauService.queryUserBillingDetails(yearMonth, recordId, appUserId)); + } catch (Exception e) { return ResultUtil.runErr(); } } @@ -171,17 +243,20 @@ @ApiOperation(value = "充值明细", tags = {"APP-使用福利"}) @ApiImplicitParams({ @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), - @ApiImplicitParam(value = "年月", name = "yearMonth", required = true, dataType = "string"), - @ApiImplicitParam(value = "记录(1充值 2扣除)", name = "recordId", required = true, dataType = "int"), + @ApiImplicitParam(value = "年月", name = "yearMonth", required = false, dataType = "string"), + @ApiImplicitParam(value = "页码", name = "pageNum", required = true, dataType = "int"), + @ApiImplicitParam(value = "每页数量", name = "pageSize", required = true, dataType = "int"), + @ApiImplicitParam(value = "记录(1充值 2扣除)", name = "recordId", required = false, dataType = "int"), }) - public ResultUtil<RechargeDetailsVo> wpGoldRechargeRecord(String yearMonth, Integer recordId){ + public ResultUtil<List<RechargesDetail>> wpGoldRechargeRecord(String yearMonth, Integer recordId, Integer pageNum, Integer pageSize) { try { Integer appUserId = tokenUtil.getUserIdFormRedis(); - if(null == appUserId){ + if (null == appUserId) { return ResultUtil.tokenErr(); } - return ResultUtil.success(rechargeRService.getAppUserRechargeRecord(yearMonth,recordId,appUserId)); - }catch (Exception e){ + return ResultUtil.success(rechargeRService.getAppUserRechargeRecord(yearMonth, recordId, appUserId, pageNum, pageSize)); + } catch (Exception e) { + e.printStackTrace(); return ResultUtil.runErr(); } } @@ -193,40 +268,283 @@ @ApiImplicitParams({ @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), }) - public ResultUtil<List<RechargeCentVo>> rechargeCenterConfig(){ + public ResultUtil<List<RechargeCentVo>> rechargeCenterConfig() { try { Integer appUserId = tokenUtil.getUserIdFormRedis(); - if(null == appUserId){ + if (null == appUserId) { return ResultUtil.tokenErr(); } return ResultUtil.success(tauService.getSysRechargeConfig(appUserId)); - }catch (Exception e){ + } catch (Exception e) { return ResultUtil.runErr(); } } /** - * 课时详情-支付 + * 充值中心-支付 */ @ResponseBody - @PostMapping("/api/startCource/payment") - @ApiOperation(value = "充值中心-支付", tags = {"APP-开始上课"}) + @PostMapping("/api/useBenefit/payment") + @ApiOperation(value = "充值中心-支付", tags = {"APP-使用福利"}) @ApiImplicitParams({ @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), }) - public ResultUtil rechargePayment(RechargePayRequest request){ + public ResultUtil rechargeCenPayment(RechargePayRequest request) { try { Integer userIdFormRedis = tokenUtil.getUserIdFormRedis(); - if(null == userIdFormRedis){ + if (null == userIdFormRedis) { return ResultUtil.tokenErr(); } - return rechargeRService.rechargePayment(userIdFormRedis,request); - }catch (Exception e){ + return rechargeRService.rechargeCenPayment(userIdFormRedis, request); + } catch (Exception e) { + e.printStackTrace(); return ResultUtil.runErr(); } } + /** + * 积分商城 + */ + @ResponseBody + @PostMapping("/api/useBenefit/integralMallList") + @ApiOperation(value = "积分商城", tags = {"APP-使用福利"}) + @ApiImplicitParams({ + @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), + }) + public ResultUtil<List<Goods>> pointsMallList(MallRequest request) { + return ResultUtil.success(tauService.queryAppUserIntegral(request)); + } + + + /** + * 商品详情 + */ + @ResponseBody + @PostMapping("/api/useBenefit/goodsDetails") + @ApiOperation(value = "积分商城-商品详情", tags = {"APP-使用福利"}) + @ApiImplicitParams({ + @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), + @ApiImplicitParam(value = "商品id", name = "goodId", required = true, dataType = "int"), + @ApiImplicitParam(value = "商品类型 1实物 2课包 3门票 4优惠券", name = "goodsType", required = true, dataType = "int"), + }) + public ResultUtil<ProductDetailsVo> productDetails(Integer goodId, Integer goodsType) { + try { + return ResultUtil.success(tauService.productDetails(goodId, goodsType)); + } catch (Exception e) { + return ResultUtil.runErr(); + } + } + + + @ResponseBody + @PostMapping("/api/useBenefit/goodsDetailsOne") + @ApiOperation(value = "积分商城-商品详情", tags = {"APP-使用福利"}) + @ApiImplicitParams({ + @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), + @ApiImplicitParam(value = "商品id", name = "goodId", required = true, dataType = "int"), + }) + public ResultUtil<ProductDetailsVo> goodsDetailsOne(Integer goodId) { + try { + return ResultUtil.success(tauService.goodsDetailsOne(goodId)); + } catch (Exception e) { + return ResultUtil.runErr(); + } + } + + + /** + * 实体、门票、优惠券为默认门店|课包为默认学员 + */ + @ResponseBody + @PostMapping("/api/useBenefit/goodsOfCourseStore") + @ApiOperation(value = "积分商城-实体、门票、优惠券为默认门店|课包为默认学员", tags = {"APP-使用福利"}) + @ApiImplicitParams({ + @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), + @ApiImplicitParam(value = "纬度", name = "lat", required = false, dataType = "String"), + @ApiImplicitParam(value = "经度", name = "lon", required = false, dataType = "String"), + @ApiImplicitParam(value = "是否为课包商品(1=是 2=否)", name = "isCourse", required = true, dataType = "int"), + @ApiImplicitParam(value = "商品id", name = "pointsMerId", required = true, dataType = "int"), + }) + public ResultUtil<StuAndStoreResponse> goodsOfCourseStore(String lat, String lon, Integer isCourse, Integer pointsMerId) { + try { + Integer userIdFormRedis = tokenUtil.getUserIdFormRedis(); + if (null == userIdFormRedis) { + return ResultUtil.tokenErr(); + } + return ResultUtil.success(tauService.queryAppUserDefaultStuAndStore(userIdFormRedis, pointsMerId, lat, lon, isCourse)); + } catch (Exception e) { + return ResultUtil.runErr(); + } + } + + + /** + * 兑换详情(实体、门票、优惠券)中的门店列表 + */ + @ResponseBody + @PostMapping("/api/useBenefit/exchangeStoreIds") + @ApiOperation(value = "积分商城-兑换详情(实体、门票、优惠券)中的门店列表", tags = {"APP-使用福利"}) + @ApiImplicitParams({ + @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), + @ApiImplicitParam(value = "商品类型 1实物 2课包 3门票 4优惠券", name = "goodsType", required = true, dataType = "String"), + @ApiImplicitParam(value = "商品id", name = "pointsMerId", required = true, dataType = "int"), + }) + public ResultUtil<List<StoreResponse>> getExchangeStoreIds(Integer goodsType, Integer pointsMerId) { + try { + return ResultUtil.success(tauService.queryStoresOfExchange(goodsType, pointsMerId)); + } catch (Exception e) { + return ResultUtil.runErr(); + } + } + + + /** + * 商品兑换 + */ + @ResponseBody + @PostMapping("/api/useBenefit/productRedemptionOperation") + @ApiOperation(value = "积分商城-商品兑换", tags = {"APP-使用福利"}) + @ApiImplicitParams({ + @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), + }) + public ResultUtil productRedemptionOperation(GoodsExchangeVo exchangeType) { + try { + Integer userIdFormRedis = tokenUtil.getUserIdFormRedis(); + if (null == userIdFormRedis) { + return ResultUtil.tokenErr(); + } + return tauService.productRedemptionOperation(userIdFormRedis, exchangeType); + } catch (Exception e) { + return ResultUtil.runErr(); + } + } + + + + + @ResponseBody + @PostMapping("/base/coupon/weChatPaymentCouponCallback") + public void weChatPaymentCouponCallback(HttpServletRequest request, HttpServletResponse response){ + try { + System.err.println("进入回调"); + Map<String, String> map = payMoneyUtil.weixinpayCallback(request); + if(null != map){ + String code = map.get("out_trade_no"); + String trade_no = map.get("transaction_id"); + String result = map.get("result"); + ResultUtil resultUtil = tauService.paymentCouponCallback(code, trade_no); + if(resultUtil.getCode() == 200){ + PrintWriter out = response.getWriter(); + out.print(result); + out.flush(); + out.close(); + } + } + }catch (Exception e){ + e.printStackTrace(); + } + } + + + + @ResponseBody + @PostMapping("/base/coupon/aliPaymentCouponCallback") + public void aliPaymentCouponCallback(HttpServletRequest request, HttpServletResponse response){ + try { + Map<String, String> map = payMoneyUtil.alipayCallback(request); + if(null != map){ + String code = map.get("out_trade_no"); + String trade_no = map.get("trade_no"); + ResultUtil resultUtil = tauService.paymentCouponCallback(code, trade_no); + if(resultUtil.getCode() == 200){ + PrintWriter out = response.getWriter(); + out.print("success"); + out.flush(); + out.close(); + } + } + }catch (Exception e){ + e.printStackTrace(); + } + } + + + + + + + + /** + * 积分明细 + */ + @ResponseBody + @PostMapping("/api/useBenefit/integralDetails") + @ApiOperation(value = "积分商城-积分明细", tags = {"APP-使用福利"}) + @ApiImplicitParams({ + @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), + @ApiImplicitParam(value = "年月", name = "yearMonth", required = false, dataType = "string"), + @ApiImplicitParam(value = "记录(1充值 2扣除)", name = "recordId", required = false, dataType = "int"), + }) + public ResultUtil<List<IntegralsData>> pointDetails(String yearMonth, Integer recordId) { + try { + Integer userIdFormRedis = tokenUtil.getUserIdFormRedis(); + if (null == userIdFormRedis) { + return ResultUtil.tokenErr(); + } + return ResultUtil.success(uicService.queryUserPointsDetails(yearMonth, recordId, userIdFormRedis)); + } catch (Exception e) { + return ResultUtil.runErr(); + } + } + + + /** + * 兑换记录 + */ + @ResponseBody + @PostMapping("/api/useBenefit/exchangeRecords") + @ApiOperation(value = "积分商城-兑换记录", tags = {"APP-使用福利"}) + @ApiImplicitParams({ + @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), + @ApiImplicitParam(value = "使用状态 (1已使用 2未使用)", name = "useType", required = false, dataType = "string"), + @ApiImplicitParam(value = "商品类型 1实物 2课包 3门票 4优惠券", name = "goodType", required = false, dataType = "int"), + @ApiImplicitParam(value = "page", name = "页数", required = true, dataType = "int"), + @ApiImplicitParam(value = "size", name = "size", required = true, dataType = "int"), + }) + public ResultUtil<List<ExchangeDetailsResponse>> exchangeRecordsDetails(Integer useType, Integer goodType, Integer page, Integer size) { + try { + if (page == null || size == null) { + page = 1; + size = 10; + } + Integer userIdFormRedis = tokenUtil.getUserIdFormRedis(); + if (null == userIdFormRedis) { + return ResultUtil.tokenErr(); + } + return ResultUtil.success(uicService.queryExchangeGoodsdetails1(userIdFormRedis, useType, goodType, page, size)); + } catch (Exception e) { + return ResultUtil.runErr(); + } + } + + + /** + * 兑换记录详情 + */ + @ResponseBody + @PostMapping("/api/useBenefit/redemptionDetails") + @ApiOperation(value = "积分商城-兑换记录详情", tags = {"APP-使用福利"}) + @ApiImplicitParams({ + @ApiImplicitParam(name = "Authorization", value = "Bearer +token", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9....."), + @ApiImplicitParam(value = "记录id", name = "detailsId", required = true, dataType = "string"), + }) + public ResultUtil<PointDetailsVo> redemptionDetails(Long detailsId) { + PointDetailsVo pointDetailsVo = uicService.queryRedemptionDetails(detailsId); + pointDetailsVo.getPics().remove(0); + return ResultUtil.success(pointDetailsVo); + } + } -- Gitblit v1.7.1