mirror of
https://github.com/iflytek/skillhub.git
synced 2026-10-10 03:27:54 +00:00
fix: hide hidden skills from slug resolution
This commit is contained in:
parent
93b5b84d17
commit
f0a9714644
6 changed files with 181 additions and 4 deletions
2
Makefile
2
Makefile
|
|
@ -10,7 +10,7 @@ DEV_API_URL := http://localhost:8080
|
|||
STAGING_API_URL := http://localhost:8080
|
||||
STAGING_WEB_URL := http://localhost
|
||||
STAGING_SERVER_IMAGE := skillhub-server:staging
|
||||
DEV_PROCESS := python3 scripts/dev_process.py
|
||||
DEV_PROCESS := bash scripts/dev-process.sh
|
||||
DEV_SERVER_PREPARE := true
|
||||
DEV_SERVER_CMD := ./scripts/run-dev-app.sh
|
||||
BACKEND_TEST_JAVA_OPTIONS ?= -XX:+EnableDynamicAgentLoading
|
||||
|
|
|
|||
156
scripts/dev-process.sh
Executable file
156
scripts/dev-process.sh
Executable file
|
|
@ -0,0 +1,156 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
echo "Usage:" >&2
|
||||
echo " $0 status --pid-file <file>" >&2
|
||||
echo " $0 stop --pid-file <file>" >&2
|
||||
echo " $0 start --pid-file <file> --log-file <file> --cwd <dir> -- <command...>" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
require_value() {
|
||||
local flag="$1"
|
||||
local value="${2:-}"
|
||||
if [[ -z "$value" ]]; then
|
||||
echo "Missing value for $flag" >&2
|
||||
usage
|
||||
fi
|
||||
}
|
||||
|
||||
resolve_path() {
|
||||
local path="$1"
|
||||
if [[ "$path" = /* ]]; then
|
||||
printf '%s\n' "$path"
|
||||
else
|
||||
printf '%s/%s\n' "$(pwd)" "$path"
|
||||
fi
|
||||
}
|
||||
|
||||
is_running() {
|
||||
local pid_file="$1"
|
||||
[[ -f "$pid_file" ]] || return 1
|
||||
|
||||
local pid
|
||||
pid="$(cat "$pid_file" 2>/dev/null || true)"
|
||||
[[ "$pid" =~ ^[0-9]+$ ]] || return 1
|
||||
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
rm -f "$pid_file"
|
||||
return 1
|
||||
}
|
||||
|
||||
wait_for_exit() {
|
||||
local pid="$1"
|
||||
for _ in $(seq 1 50); do
|
||||
if ! kill -0 "$pid" 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
cmd="${1:-}"
|
||||
[[ -n "$cmd" ]] || usage
|
||||
shift || true
|
||||
|
||||
pid_file=""
|
||||
log_file=""
|
||||
cwd=""
|
||||
|
||||
case "$cmd" in
|
||||
status|stop)
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--pid-file)
|
||||
require_value "$1" "${2:-}"
|
||||
pid_file="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
[[ -n "$pid_file" ]] || usage
|
||||
;;
|
||||
start)
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--pid-file)
|
||||
require_value "$1" "${2:-}"
|
||||
pid_file="$2"
|
||||
shift 2
|
||||
;;
|
||||
--log-file)
|
||||
require_value "$1" "${2:-}"
|
||||
log_file="$2"
|
||||
shift 2
|
||||
;;
|
||||
--cwd)
|
||||
require_value "$1" "${2:-}"
|
||||
cwd="$2"
|
||||
shift 2
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
[[ -n "$pid_file" && -n "$log_file" && -n "$cwd" && $# -gt 0 ]] || usage
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$cmd" in
|
||||
status)
|
||||
is_running "$pid_file"
|
||||
;;
|
||||
stop)
|
||||
if ! is_running "$pid_file"; then
|
||||
rm -f "$pid_file"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
pid="$(cat "$pid_file")"
|
||||
kill "$pid" 2>/dev/null || true
|
||||
if ! wait_for_exit "$pid"; then
|
||||
kill -9 "$pid" 2>/dev/null || true
|
||||
wait_for_exit "$pid" || true
|
||||
fi
|
||||
rm -f "$pid_file"
|
||||
;;
|
||||
start)
|
||||
pid_file="$(resolve_path "$pid_file")"
|
||||
log_file="$(resolve_path "$log_file")"
|
||||
cwd="$(resolve_path "$cwd")"
|
||||
mkdir -p "$(dirname "$pid_file")" "$(dirname "$log_file")"
|
||||
if is_running "$pid_file"; then
|
||||
echo "Process already running with PID $(cat "$pid_file")" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
(
|
||||
cd "$cwd"
|
||||
if command -v setsid >/dev/null 2>&1; then
|
||||
setsid "$@" >>"$log_file" 2>&1 < /dev/null &
|
||||
else
|
||||
nohup "$@" >>"$log_file" 2>&1 < /dev/null &
|
||||
fi
|
||||
child_pid=$!
|
||||
disown "$child_pid" 2>/dev/null || true
|
||||
echo "$child_pid" >"$pid_file"
|
||||
)
|
||||
;;
|
||||
esac
|
||||
|
|
@ -95,7 +95,7 @@ class AdminSkillReportControllerTest {
|
|||
report.setStatus(com.iflytek.skillhub.domain.report.SkillReportStatus.RESOLVED);
|
||||
when(skillReportService.resolveReport(
|
||||
org.mockito.ArgumentMatchers.eq(99L),
|
||||
org.mockito.ArgumentMatchers.eq("admin"),
|
||||
org.mockito.ArgumentMatchers.eq("super-admin"),
|
||||
org.mockito.ArgumentMatchers.eq(SkillReportDisposition.RESOLVE_AND_HIDE),
|
||||
org.mockito.ArgumentMatchers.eq("handled"),
|
||||
org.mockito.ArgumentMatchers.any(),
|
||||
|
|
@ -103,7 +103,7 @@ class AdminSkillReportControllerTest {
|
|||
.thenReturn(report);
|
||||
|
||||
mockMvc.perform(post("/api/v1/admin/skill-reports/99/resolve")
|
||||
.with(authentication(adminAuth()))
|
||||
.with(authentication(superAdminAuth()))
|
||||
.with(csrf())
|
||||
.contentType(APPLICATION_JSON)
|
||||
.content("{\"comment\":\"handled\",\"disposition\":\"RESOLVE_AND_HIDE\"}"))
|
||||
|
|
@ -147,4 +147,13 @@ class AdminSkillReportControllerTest {
|
|||
principal, null, List.of(new SimpleGrantedAuthority("ROLE_SKILL_ADMIN"))
|
||||
);
|
||||
}
|
||||
|
||||
private UsernamePasswordAuthenticationToken superAdminAuth() {
|
||||
PlatformPrincipal principal = new PlatformPrincipal(
|
||||
"super-admin", "super-admin", "admin@example.com", "", "github", Set.of("SUPER_ADMIN")
|
||||
);
|
||||
return new UsernamePasswordAuthenticationToken(
|
||||
principal, null, List.of(new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,8 +82,10 @@ class SkillSearchAppServiceTest {
|
|||
void search_shouldFillVisiblePageAcrossArchivedNamespaceResults() {
|
||||
Skill archivedSkill = new Skill(1L, "archived-skill", "owner-1", SkillVisibility.PUBLIC);
|
||||
setField(archivedSkill, "id", 10L);
|
||||
archivedSkill.setLatestVersionId(110L);
|
||||
Skill visibleSkill = new Skill(2L, "visible-skill", "owner-1", SkillVisibility.PUBLIC);
|
||||
setField(visibleSkill, "id", 11L);
|
||||
visibleSkill.setLatestVersionId(111L);
|
||||
|
||||
Namespace archivedNamespace = new Namespace("archived-team", "Archived Team", "owner-1");
|
||||
setField(archivedNamespace, "id", 1L);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class SkillSlugResolutionService {
|
|||
? Optional.empty()
|
||||
: skills.stream().filter(skill -> currentUserId.equals(skill.getOwnerId())).findFirst();
|
||||
Optional<Skill> publishedSkill = skills.stream()
|
||||
.filter(skill -> skill.getLatestVersionId() != null)
|
||||
.filter(skill -> skill.getLatestVersionId() != null && !skill.isHidden())
|
||||
.findFirst();
|
||||
|
||||
if (preference == Preference.CURRENT_USER) {
|
||||
|
|
|
|||
|
|
@ -58,6 +58,16 @@ class SkillSlugResolutionServiceTest {
|
|||
service.resolve(1L, "demo", null, SkillSlugResolutionService.Preference.CURRENT_USER));
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwsWhenOnlyPublishedSkillIsHiddenFromCurrentUser() throws Exception {
|
||||
Skill hiddenPublishedSkill = createSkill(4L, "demo", "user-2", 44L);
|
||||
hiddenPublishedSkill.setHidden(true);
|
||||
when(skillRepository.findByNamespaceIdAndSlug(1L, "demo")).thenReturn(List.of(hiddenPublishedSkill));
|
||||
|
||||
assertThrows(DomainBadRequestException.class, () ->
|
||||
service.resolve(1L, "demo", "user-9", SkillSlugResolutionService.Preference.CURRENT_USER));
|
||||
}
|
||||
|
||||
private Skill createSkill(Long id, String slug, String ownerId, Long latestVersionId) throws Exception {
|
||||
Skill skill = new Skill(1L, slug, ownerId, SkillVisibility.PUBLIC);
|
||||
Field idField = Skill.class.getDeclaredField("id");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue