Skip to content

Commit

Permalink
feat: adapt NON-ADMIN users (#7)
Browse files Browse the repository at this point in the history
适配非 ADMIN 用户 #3 (comment)
处理下载链接编码问题 #5 (comment)
/kind improvement

```release-note
None
```
  • Loading branch information
Roozenlz authored Aug 5, 2024
1 parent 47dc8a2 commit ec2ad22
Show file tree
Hide file tree
Showing 12 changed files with 150 additions and 51 deletions.
25 changes: 16 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,30 @@ AList 存储库插件,支持创建 AList 类型的存储库
## 使用方式

首先[部署一个 AList 服务](https://alist.nn.ci/zh/guide/install/docker.html),进入后台管理,创建存储库

![](docs/img/1.png)
根据文档填写相关信息,注意这里的挂载路径

根据 [AList 文档](https://alist.nn.ci/zh/guide/) 填写相关信息

![](docs/img/2.png)

安装并启用此插件后,在 Halo 后台新建存储策略

![](docs/img/3.png)

选择 AList 存储

![](docs/img/4.png)

根据提示填写以下信息

![](docs/img/5.png)

![](docs/img/6.png)

你填写的用户应该至少拥有以下权限,这里的基本路径就是挂载路径的上级路径

![](docs/img/9.png)
![](docs/img/7.png)

## 注意事项
Expand All @@ -26,6 +40,7 @@ AList 存储库插件,支持创建 AList 类型的存储库
client_max_body_size 0;
```
![](docs/img/8.png)
3. 修改用户状态后需要重新验证来刷新缓存,如:修改用户密码
## 开发环境
插件开发的详细文档请查阅:<https://docs.halo.run/developer-guide/plugin/introduction>
Expand Down Expand Up @@ -55,14 +70,6 @@ cd path/to/plugin-alist

> 此方式需要本地安装 Docker
```bash
# macOS / Linux
./gradlew pnpmInstall

# Windows
./gradlew.bat pnpmInstall
```

```bash
# macOS / Linux
./gradlew haloServer
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ tasks.withType(JavaCompile).configureEach {
}

halo {
version = '2.17'
version = '2.18'
superAdminUsername = 'admin'
superAdminPassword = 'admin'
externalUrl = 'http://localhost:8090'
Expand Down
Binary file added docs/img/10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/img/5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/img/7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version=1.0.0
version=1.0.1
2 changes: 1 addition & 1 deletion src/main/java/run/halo/alist/config/AListProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class AListProperties {
*/
private String site;
/**
* AList 挂载路径.
* AList 基本路径下文件夹的路径.
*/
private String path;
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
package run.halo.alist.controller;

import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import run.halo.alist.endpoint.AListAttachmentHandler;
import run.halo.alist.config.AListProperties;
import run.halo.alist.dto.AListResult;
import run.halo.alist.dto.response.AListStorageListRes;
import run.halo.alist.dto.request.AListGetFileInfoReq;
import run.halo.alist.dto.response.AListGetCurrentUserInfoRes;
import run.halo.alist.dto.response.AListGetFileInfoRes;
import run.halo.alist.endpoint.AListAttachmentHandler;
import run.halo.alist.exception.AListIllegalArgumentException;
import run.halo.app.plugin.ApiVersion;

Expand All @@ -38,28 +39,68 @@ public Mono<Void> validatePolicyConfig(@RequestBody AListProperties properties)
.flatMap(token -> handler.getWebClients()
.get(properties.getSite())
.get()
.uri("/api/admin/storage/list")
.header("Authorization", token)
.uri("/api/me")
.header(HttpHeaders.AUTHORIZATION, token)
.retrieve()
.bodyToMono(
new ParameterizedTypeReference<AListResult<AListStorageListRes>>() {
new ParameterizedTypeReference<AListResult<AListGetCurrentUserInfoRes>>() {
})
.flatMap(response -> {
if (response.getCode().equals("200")) {
return Flux.fromIterable(response.getData().getContent())
.filter(volume -> Objects.equals(volume.getMountPath(),
properties.getPath()))
.switchIfEmpty(Mono.error(new AListIllegalArgumentException(
"The mount path does not exist")))
.all(volume -> !volume.isDisabled())
.filter(isValid -> isValid)
.switchIfEmpty(Mono.error(new AListIllegalArgumentException(
"The storage is disabled")))
.then();
if (response.getCode().equals("401")) {
return Mono.error(new AListIllegalArgumentException(
"Current user is disabled"));
}
if (!response.getCode().equals("200")) {
return Mono.error(new AListIllegalArgumentException(
"Wrong Username Or Password"));
}
return Mono.error(new AListIllegalArgumentException(
"Wrong Username Or Password"));
}))
AListGetCurrentUserInfoRes userInfo = response.getData();
return handler.getWebClients()
.get(properties.getSite())
.post()
.uri("/api/fs/get")
.header(HttpHeaders.AUTHORIZATION, token)
.body(Mono.just(AListGetFileInfoReq.builder()
.path("/")
.build()),
AListGetFileInfoReq.class)
.retrieve()
.bodyToMono(
new ParameterizedTypeReference<AListResult<AListGetFileInfoRes>>() {
})
.flatMap(res -> {
// 验证当前基本路径是否可用
if (!res.getCode().equals("200")) {
return Mono.error(
new AListIllegalArgumentException(res.getMessage()));
}
// 管理员用户拥有所有权限
if (userInfo.getRole() == 2) {
return Mono.empty();
}
// 普通用户验证权限
int permission = userInfo.getPermission();
StringBuilder sb = new StringBuilder();
if ((permission & 2) == 0) {
sb.append("无需密码访问权限 ");
}
if ((permission & 8) == 0) {
sb.append("创建目录或上传权限 ");
}
if ((permission & 128) == 0) {
sb.append("删除权限 ");
}
if (!sb.isEmpty()) {
sb.append("未开启");
return Mono.error(
new AListIllegalArgumentException(sb.toString()));
}
return Mono.empty();
});

})

)
);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package run.halo.alist.dto.response;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* @author <a href="https://roozen.top">Roozen</a>
* @version 1.0
* 2024/8/2
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AListGetCurrentUserInfoRes {
private int id;
private String username;
private String password;
/**
* 基本路径
*/
@JsonProperty("base_path")
private String basePath;
private int role;
private boolean disabled;
private int permission;
@JsonProperty("sso_id")
private String ssoId;
/**
* 是否开启二步验证
*/
private boolean otp;
}
48 changes: 32 additions & 16 deletions src/main/java/run/halo/alist/endpoint/AListAttachmentHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientRequestException;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriUtils;
import reactor.core.publisher.Mono;
Expand All @@ -33,6 +34,7 @@
import run.halo.alist.dto.request.AListGetFileInfoReq;
import run.halo.alist.dto.request.AListLoginReq;
import run.halo.alist.dto.request.AListRemoveFileReq;
import run.halo.alist.dto.response.AListGetCurrentUserInfoRes;
import run.halo.alist.dto.response.AListGetFileInfoRes;
import run.halo.alist.dto.response.AListLoginRes;
import run.halo.alist.dto.response.AListUploadAsTaskRes;
Expand Down Expand Up @@ -117,11 +119,8 @@ public Mono<Attachment> upload(UploadContext uploadContext) {
var metadata = new Metadata();
metadata.setName(UUID.randomUUID().toString());
metadata.setAnnotations(
Map.of(Constant.EXTERNAL_LINK_ANNO_KEY,
UriUtils.encodePath(
properties.getSite() + "/d" + properties.getPath() + "/"
+ file.name(),
StandardCharsets.UTF_8)));
Map.of(Constant.EXTERNAL_LINK_ANNO_KEY, ""));

var spec = new Attachment.AttachmentSpec();
SimpleFilePart simpleFilePart = (SimpleFilePart) file;
spec.setDisplayName(simpleFilePart.filename());
Expand Down Expand Up @@ -183,7 +182,9 @@ public Mono<String> auth(AListProperties properties) {
.retrieve()
.bodyToMono(
new ParameterizedTypeReference<AListResult<AListLoginRes>>() {
});
})
.onErrorMap(WebClientRequestException.class,
e -> new AListIllegalArgumentException(e.getMessage()));
}).flatMap(response -> {
if (response.getCode().equals("200")) {
log.info("[AList Info] : Login successfully");
Expand All @@ -198,7 +199,12 @@ public Mono<String> auth(AListProperties properties) {

private AListProperties getProperties(ConfigMap configMap) {
var settingJson = configMap.getData().getOrDefault("default", "{}");
return JsonUtils.jsonToObject(settingJson, AListProperties.class);
AListProperties aListProperties =
JsonUtils.jsonToObject(settingJson, AListProperties.class);
if (aListProperties.getPath().equals("/")) {
aListProperties.setPath("");
}
return aListProperties;
}

@Override
Expand Down Expand Up @@ -264,15 +270,25 @@ public Mono<URI> getPermalink(Attachment attachment, Policy policy, ConfigMap co
}
return Mono.error(new AListRequestErrorException(response.getMessage()));
}))
.map(response -> UriComponentsBuilder.fromHttpUrl(properties.getSite())
.path("/d/{path}/{name}")
.queryParamIfPresent("sign",
Optional.ofNullable(response.getData().getSign()).filter(s -> !s.isEmpty()))
.buildAndExpand(
UriUtils.encodePath(properties.getPath(), StandardCharsets.UTF_8),
UriUtils.encodePath(response.getData().getName(), StandardCharsets.UTF_8)
)
.toUri());
.flatMap(response -> webClients.get(properties.getSite())
.get()
.uri("/api/me")
.header(HttpHeaders.AUTHORIZATION,
tokenCache.getIfPresent(properties.getTokenKey()))
.retrieve()
.bodyToMono(
new ParameterizedTypeReference<AListResult<AListGetCurrentUserInfoRes>>() {
})
.map(res -> UriComponentsBuilder.fromHttpUrl(properties.getSite())
.path("/d{basePath}{path}/{name}")
.queryParamIfPresent("sign",
Optional.ofNullable(response.getData().getSign()).filter(s -> !s.isEmpty()))
.buildAndExpand(
res.getData().getBasePath(),
properties.getPath(),
response.getData().getName()
)
.toUri()));
}

boolean shouldHandle(Policy policy) {
Expand Down
3 changes: 1 addition & 2 deletions src/main/resources/extensions/policy-template-alist.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ spec:
- $formkit: text
name: path
label: 挂载路径
validation: required
help: AList 存储中的挂载路径,必须以 / 开头,如 /aliyun
help: 所填用户基本路径(可在 AList 管理 -> 用户 查看)下文件夹的路径,必须以 / 开头,支持多级目录如 /picture/2024,则全路径为{基本路径}/picture/2024,上传文件时会自动创建不存在的目录,为 / 时留空即可
- $formkit: secret
name: secretName
required: true
Expand Down

0 comments on commit ec2ad22

Please sign in to comment.