Skip to content

Commit

Permalink
fix: attachment table field. feat: cache expiration for checkin code.…
Browse files Browse the repository at this point in the history
… feat: get event invitee.
  • Loading branch information
ballade0d committed Oct 20, 2024
1 parent 1878816 commit 9d64368
Show file tree
Hide file tree
Showing 23 changed files with 290 additions and 151 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<version>3.3.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.qingyou</groupId>
<groupId>fun.sast</groupId>
<artifactId>sast-evento-lark</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sast-evento-lark</name>
Expand All @@ -20,7 +20,7 @@
<dependency>
<groupId>fun.feellmoose</groupId>
<artifactId>sast-link-sdk</artifactId>
<version>0.1.2</version>
<version>0.1.3</version>
</dependency>
<dependency>
<groupId>com.larksuite.oapi</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ void invite(@PathVariable Long eventId, @RequestBody List<V2.LarkUser> users) {

@GetMapping("/{eventId}/invite")
@RequirePermission(Permission.MANAGER)
List<V2.LarkUser> invite(@PathVariable Long eventId) {
return eventService.getAttendees(eventId);
List<V2.LarkUser> getAttendees(@PathVariable Long eventId) {
return eventService.getAttendees(eventId).stream().map(user -> new V2.LarkUser(
user.openId(),
user.name(),
user.avatar()
)).toList();
}
}
17 changes: 13 additions & 4 deletions src/main/java/fun/sast/evento/lark/api/client/EventController.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package fun.sast.evento.lark.api.client;

import fun.sast.evento.lark.api.security.Permission;
import fun.sast.evento.lark.api.security.RequirePermission;
import fun.sast.evento.lark.api.value.V2;
import fun.sast.evento.lark.domain.common.value.Pagination;
import fun.sast.evento.lark.domain.event.entity.Event;
import fun.sast.evento.lark.domain.event.service.EventService;
import fun.sast.evento.lark.domain.event.value.EventQuery;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.List;

@RestController
@RequestMapping("/api/v2/client/event")
Expand Down Expand Up @@ -56,4 +56,13 @@ Pagination<V2.Event> query(@RequestParam(value = "page", required = false, defau
events.total()
);
}

@GetMapping("/{eventId}/invite")
List<V2.LarkUser> getAttendees(@PathVariable Long eventId) {
return eventService.getAttendees(eventId).stream().map(user -> new V2.LarkUser(
null,
user.name(),
user.avatar()
)).toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class LoginController {
UserService userService;

@PostMapping("/link")
V2.Login link(@RequestParam String code, @RequestParam Integer type) {
return userService.login(code);
V2.Login link(@RequestParam String code, @RequestParam Integer type, @RequestParam String codeVerifier) {
return userService.login(code, type, codeVerifier);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ public class Attachment {
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
private Long eventId;
private String key;
private String ossKey;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
@Data
@TableName("user")
public class User {
@TableId(value = "id", type = IdType.INPUT)
@TableId(value = "user_id", type = IdType.INPUT)
private String userId;
private Integer permission;
@TableField(exist = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import fun.sast.evento.lark.domain.event.value.EventCreate;
import fun.sast.evento.lark.domain.event.value.EventQuery;
import fun.sast.evento.lark.domain.event.value.EventUpdate;
import fun.sast.evento.lark.domain.lark.value.LarkUser;

import java.util.List;

Expand All @@ -29,7 +30,7 @@ public interface EventService {

void invite(Long eventId, List<V2.LarkUser> users);

List<V2.LarkUser> getAttendees(Long eventId);
List<LarkUser> getAttendees(Long eventId);

V2.Event mapToV2(Event event);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

public interface UserService {

V2.Login login(String code);
V2.Login login(String code, Integer type, String codeVerifier);

Boolean assignManagerRole(String userId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public Attachment uploadAttachment(Long eventId, MultipartFile file) {
String key = oss.upload(file);
Attachment attachment = new Attachment();
attachment.setEventId(eventId);
attachment.setKey(key);
attachment.setOssKey(key);
attachmentMapper.insert(attachment);
return attachment;
}
Expand All @@ -47,7 +47,7 @@ public Boolean deleteAttachment(Long eventId, Long attachmentId) {
if (!attachment.getEventId().equals(eventId)) {
throw new BusinessException(ErrorEnum.PARAM_ERROR, "Unexpected attachment");
}
oss.delete(attachment.getKey());
oss.delete(attachment.getOssKey());
return attachmentMapper.deleteById(attachmentId) > 0;
}

Expand All @@ -63,7 +63,7 @@ public V2.Attachment mapToV2(Attachment attachment) {
return new V2.Attachment(
attachment.getId(),
attachment.getEventId().toString(),
oss.url(attachment.getKey()).toString()
oss.url(attachment.getOssKey()).toString()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lark.oapi.service.calendar.v4.model.CalendarEventAttendee;
import com.lark.oapi.service.calendar.v4.model.TimeInfo;
import fun.sast.evento.lark.api.value.V2;
import fun.sast.evento.lark.domain.common.value.Constants;
Expand All @@ -16,15 +17,18 @@
import fun.sast.evento.lark.domain.lark.service.LarkDepartmentService;
import fun.sast.evento.lark.domain.lark.service.LarkEventService;
import fun.sast.evento.lark.domain.lark.service.LarkRoomService;
import fun.sast.evento.lark.domain.lark.service.LarkUserService;
import fun.sast.evento.lark.domain.lark.value.LarkEventCreate;
import fun.sast.evento.lark.domain.lark.value.LarkEventUpdate;
import fun.sast.evento.lark.domain.lark.value.LarkUser;
import fun.sast.evento.lark.domain.subscription.service.MessageService;
import fun.sast.evento.lark.infrastructure.auth.JWTInterceptor;
import fun.sast.evento.lark.infrastructure.error.BusinessException;
import fun.sast.evento.lark.infrastructure.error.ErrorEnum;
import fun.sast.evento.lark.infrastructure.repository.EventMapper;
import fun.sast.evento.lark.infrastructure.utils.TimeUtils;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
Expand All @@ -40,15 +44,19 @@ public class EventServiceImpl implements EventService {
@Resource
private LarkRoomService larkRoomService;
@Resource
private LarkUserService larkUserService;
@Resource
private SubscriptionService subscriptionService;
@Resource
private MessageService messageService;
@Resource
private EventMapper eventMapper;
@Value("${app.lark.check-room-availability}")
private Boolean checkRoomAvailability;

@Override
public Event create(EventCreate create) {
if (create.larkMeetingRoomId() != null && !larkRoomService.isAvailable(create.larkMeetingRoomId(), create.start(), create.end())) {
if (checkRoomAvailability && create.larkMeetingRoomId() != null && !larkRoomService.isAvailable(create.larkMeetingRoomId(), create.start(), create.end())) {
throw new BusinessException(ErrorEnum.PARAM_ERROR, "meeting room is not available");
}
if (create.larkDepartmentId() == null) {
Expand Down Expand Up @@ -100,17 +108,17 @@ public Event update(Long eventId, EventUpdate update) {
}
// if room == null -> remove room
// if room != null && room != old room -> update room
String larkMeetingRoomName = update.larkMeetingRoomId() == null ? null : larkRoomService.get(update.larkMeetingRoomId()).name();
if (update.larkMeetingRoomId() != null &&
!larkMeetingRoomName.equals(event.getLarkMeetingRoomName()) &&
!larkRoomService.isAvailable(update.larkMeetingRoomId(), update.start(), update.end())) {
throw new BusinessException(ErrorEnum.PARAM_ERROR, "meeting room is not available");
}
LocalDateTime start = update.start() == null ? event.getStart() : update.start();
LocalDateTime end = update.end() == null ? event.getEnd() : update.end();
if (start.isAfter(end)) {
throw new BusinessException(ErrorEnum.PARAM_ERROR, "start time should be before end time");
}
String larkMeetingRoomName = update.larkMeetingRoomId() == null ? null : larkRoomService.get(update.larkMeetingRoomId()).name();
if (checkRoomAvailability && update.larkMeetingRoomId() != null &&
!larkMeetingRoomName.equals(event.getLarkMeetingRoomName()) &&
!larkRoomService.isAvailable(update.larkMeetingRoomId(), start, end)) {
throw new BusinessException(ErrorEnum.PARAM_ERROR, "meeting room is not available");
}
larkEventService.update(event.getLarkEventUid(), new LarkEventUpdate(
update.summary(),
update.description(),
Expand Down Expand Up @@ -227,18 +235,15 @@ public void invite(Long eventId, List<V2.LarkUser> users) {
}

@Override
public List<V2.LarkUser> getAttendees(Long eventId) {
public List<LarkUser> getAttendees(Long eventId) {
Event event = eventMapper.selectById(eventId);
if (event == null) {
throw new BusinessException(ErrorEnum.PARAM_ERROR, "event not found");
}
return larkEventService.getAttendees(event.getLarkEventUid(), Constants.LARK_ATTENDEE_TYPE_USER)
return larkUserService.list(larkEventService.getAttendees(event.getLarkEventUid(), Constants.LARK_ATTENDEE_TYPE_USER)
.stream()
.map(attendee -> new V2.LarkUser(
attendee.getUserId(),
null,
null))
.toList();
.map(CalendarEventAttendee::getUserId)
.toList());
}

private void scheduleStateUpdate(Event event) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@
import fun.sast.evento.lark.domain.event.service.SubscriptionService;
import fun.sast.evento.lark.domain.subscription.event.EventStateUpdateEvent;
import fun.sast.evento.lark.domain.subscription.service.impl.EventStateUpdatePublishService;
import fun.sast.evento.lark.infrastructure.cache.RedisCache;
import fun.sast.evento.lark.infrastructure.error.BusinessException;
import fun.sast.evento.lark.infrastructure.error.ErrorEnum;
import fun.sast.evento.lark.infrastructure.repository.DepartmentSubscriptionMapper;
import fun.sast.evento.lark.infrastructure.repository.SubscriptionMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.security.SecureRandom;
import java.util.Base64;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
Expand All @@ -31,7 +31,7 @@ public class SubscriptionServiceImpl implements SubscriptionService {
@Resource
private DepartmentSubscriptionMapper departmentSubscriptionMapper;
@Resource
private CacheManager cacheManager;
private RedisCache redisCache;
@Resource
private EventStateUpdatePublishService eventStateUpdatePublishService;

Expand All @@ -41,26 +41,17 @@ public String generateCheckInCode(Long eventId) {
byte[] bytes = new byte[5];
random.nextBytes(bytes);
String code = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes).substring(0, 5);
Cache cache = cacheManager.getCache("checkin-code");
if (cache == null) {
log.error("checkin-code cache not found");
throw new RuntimeException("checkin-code cache not found");
}
cache.put(code, eventId.toString());
redisCache.set("checkin-code::" + code, eventId, 10, TimeUnit.MINUTES);
return code;
}

@Override
public Boolean checkIn(Long eventId, String linkId, String code) {
Cache cache = cacheManager.getCache("checkin-code");
if (cache == null) {
return false;
}
String matchedId = cache.get(code, String.class);
Long matchedId = redisCache.get("checkin-code::" + code, Long.class);
if (matchedId == null) {
throw new BusinessException(ErrorEnum.CHECKIN_CODE_NOT_EXISTS, "checkin-code not exists or has expired");
}
if (!matchedId.equals(eventId.toString())) {
if (!matchedId.equals(eventId)) {
throw new BusinessException(ErrorEnum.CHECKIN_CODE_NOT_EXISTS, "checkin-code not match");
}
QueryWrapper<Subscription> queryWrapper = new QueryWrapper<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import fun.sast.evento.lark.domain.event.entity.User;
import fun.sast.evento.lark.domain.event.service.UserService;
import fun.sast.evento.lark.infrastructure.auth.JWTService;
import fun.sast.evento.lark.infrastructure.error.BusinessException;
import fun.sast.evento.lark.infrastructure.repository.UserMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -21,7 +20,9 @@
public class UserServiceImpl implements UserService {

@Resource
private SastLinkService sastLinkService;
private SastLinkService sastLinkServiceWeb;
@Resource
private SastLinkService sastLinkServiceApp;
@Resource
private JWTService jwtService;
@Resource
Expand All @@ -30,8 +31,9 @@ public class UserServiceImpl implements UserService {
private CacheManager cacheManager;

@Override
public V2.Login login(String code) {
AccessToken accessToken = sastLinkService.accessToken(code);
public V2.Login login(String code, Integer type, String codeVerifier) {
SastLinkService sastLinkService = type == 1 ? sastLinkServiceWeb : sastLinkServiceApp;
AccessToken accessToken = sastLinkService.accessToken(code, codeVerifier);
UserInfo userInfo = sastLinkService.user(accessToken.getAccessToken());
User user = userMapper.selectById(userInfo.getUserId());
if (user == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package fun.sast.evento.lark.domain.lark.service;

import fun.sast.evento.lark.domain.lark.value.LarkUser;

import java.util.List;

public interface LarkUserService {

List<LarkUser> list(List<String> users);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package fun.sast.evento.lark.domain.lark.service.impl;

import com.lark.oapi.service.contact.v3.model.BatchUserReq;
import com.lark.oapi.service.contact.v3.model.BatchUserResp;
import fun.sast.evento.lark.domain.lark.service.LarkUserService;
import fun.sast.evento.lark.domain.lark.value.LarkUser;
import fun.sast.evento.lark.infrastructure.error.BusinessException;
import fun.sast.evento.lark.infrastructure.error.ErrorEnum;
import fun.sast.evento.lark.infrastructure.lark.OApi;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;

@Service
@Slf4j
public class LarkUserServiceImpl implements LarkUserService {

@Resource
private OApi oApi;

@Override
public List<LarkUser> list(List<String> users) {
if (users.isEmpty()) {
return List.of();
}
try {
String[] userIds = users.toArray(new String[0]);
BatchUserResp resp = oApi.getClient().contact().user().batch(BatchUserReq.newBuilder().userIds(userIds).build());
if (!resp.success()) {
log.error("failed to list room: {}", resp.getMsg());
throw new BusinessException(ErrorEnum.LARK_ERROR_LIST_USER, resp.getMsg());
}
return Arrays.stream(resp.getData().getItems()).map(user -> new LarkUser(
user.getOpenId(),
user.getName(),
user.getAvatar().getAvatar240()
)).toList();
} catch (Exception e) {
log.error("list user error: {}", e.getMessage());
throw new RuntimeException(e.getMessage(), e);
}
}
}
Loading

0 comments on commit 9d64368

Please sign in to comment.