Elkins commited on
Commit
d193c91
·
verified ·
1 Parent(s): 6ea44fe

Upload 97 files

Browse files
.github/workflows/docker-release.yml ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Build WeWeRSS images and push image to docker hub
2
+ on:
3
+ workflow_dispatch:
4
+ push:
5
+ # paths:
6
+ # - "apps/**"
7
+ # - "Dockerfile"
8
+ tags:
9
+ - "v*.*.*"
10
+
11
+ concurrency:
12
+ group: docker-release
13
+ cancel-in-progress: true
14
+
15
+ jobs:
16
+ check-env:
17
+ permissions:
18
+ contents: none
19
+ runs-on: ubuntu-latest
20
+ timeout-minutes: 5
21
+ outputs:
22
+ check-docker: ${{ steps.check-docker.outputs.defined }}
23
+ steps:
24
+ - id: check-docker
25
+ env:
26
+ DOCKER_HUB_NAME: ${{ secrets.DOCKER_HUB_NAME }}
27
+ if: ${{ env.DOCKER_HUB_NAME != '' }}
28
+ run: echo "defined=true" >> $GITHUB_OUTPUT
29
+
30
+ release-images:
31
+ runs-on: ubuntu-latest
32
+ timeout-minutes: 120
33
+ permissions:
34
+ packages: write
35
+ contents: read
36
+ id-token: write
37
+ steps:
38
+ - name: Checkout
39
+ uses: actions/checkout@v4
40
+ with:
41
+ fetch-depth: 1
42
+
43
+ - name: Set up QEMU
44
+ uses: docker/setup-qemu-action@v3
45
+
46
+ - name: Set up Docker Buildx
47
+ uses: docker/setup-buildx-action@v3
48
+
49
+ - name: Login to Docker Hub
50
+ uses: docker/login-action@v2
51
+ with:
52
+ username: ${{ secrets.DOCKER_HUB_NAME }}
53
+ password: ${{ secrets.DOCKER_HUB_PASSWORD }}
54
+
55
+ - name: Login to GitHub Container Registry
56
+ uses: docker/login-action@v3
57
+ with:
58
+ registry: ghcr.io
59
+ username: ${{ github.repository_owner }}
60
+ password: ${{ secrets.GITHUB_TOKEN }}
61
+
62
+ - name: Extract Docker metadata (sqlite)
63
+ id: meta-sqlite
64
+ uses: docker/metadata-action@v5
65
+ with:
66
+ images: |
67
+ ${{ secrets.DOCKER_HUB_NAME }}/wewe-rss-sqlite
68
+ ghcr.io/cooderl/wewe-rss-sqlite
69
+ tags: |
70
+ type=raw,value=latest,enable=true
71
+ type=raw,value=${{ github.ref_name }},enable=true
72
+ flavor: latest=false
73
+
74
+ - name: Build and push Docker image (sqlite)
75
+ id: build-and-push-sqlite
76
+ uses: docker/build-push-action@v5
77
+ with:
78
+ context: .
79
+ push: true
80
+ tags: ${{ steps.meta-sqlite.outputs.tags }}
81
+ labels: ${{ steps.meta-sqlite.outputs.labels }}
82
+ target: app-sqlite
83
+ platforms: linux/amd64,linux/arm64
84
+ cache-from: type=gha,scope=docker-release
85
+ cache-to: type=gha,mode=max,scope=docker-release
86
+
87
+ - name: Extract Docker metadata
88
+ id: meta
89
+ uses: docker/metadata-action@v5
90
+ with:
91
+ images: |
92
+ ${{ secrets.DOCKER_HUB_NAME }}/wewe-rss
93
+ ghcr.io/cooderl/wewe-rss
94
+ tags: |
95
+ type=raw,value=latest,enable=true
96
+ type=raw,value=${{ github.ref_name }},enable=true
97
+ flavor: latest=false
98
+
99
+ - name: Build and push Docker image
100
+ id: build-and-push
101
+ uses: docker/build-push-action@v5
102
+ with:
103
+ context: .
104
+ push: true
105
+ tags: ${{ steps.meta.outputs.tags }}
106
+ labels: ${{ steps.meta.outputs.labels }}
107
+ target: app
108
+ platforms: linux/amd64,linux/arm64
109
+ cache-from: type=gha,scope=docker-release
110
+ cache-to: type=gha,mode=max,scope=docker-release
111
+
112
+ - name: Set env
113
+ run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
114
+
115
+ - name: Create a Release
116
+ uses: elgohr/Github-Release-Action@v5
117
+ env:
118
+ GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
119
+ with:
120
+ title: ${{ env.RELEASE_VERSION }}
121
+
122
+ description:
123
+ runs-on: ubuntu-latest
124
+ needs: check-env
125
+ if: needs.check-env.outputs.check-docker == 'true'
126
+ timeout-minutes: 5
127
+ steps:
128
+ - uses: actions/checkout@v4
129
+
130
+ - name: Docker Hub Description(sqlite)
131
+ uses: peter-evans/dockerhub-description@v4
132
+ with:
133
+ username: ${{ secrets.DOCKER_HUB_NAME }}
134
+ password: ${{ secrets.DOCKER_HUB_PASSWORD }}
135
+ repository: ${{ secrets.DOCKER_HUB_NAME }}/wewe-rss-sqlite
136
+
137
+ - name: Docker Hub Description
138
+ uses: peter-evans/dockerhub-description@v4
139
+ with:
140
+ username: ${{ secrets.DOCKER_HUB_NAME }}
141
+ password: ${{ secrets.DOCKER_HUB_PASSWORD }}
142
+ repository: ${{ secrets.DOCKER_HUB_NAME }}/wewe-rss
.vscode/extensions.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "recommendations": [
3
+ "esbenp.prettier-vscode",
4
+ "dbaeumer.vscode-eslint",
5
+ "stylelint.vscode-stylelint",
6
+ "streetsidesoftware.code-spell-checker",
7
+ "DavidAnson.vscode-markdownlint",
8
+ "Gruntfuggly.todo-tree",
9
+ "mikestead.dotenv",
10
+ "foxundermoon.next-js",
11
+ "Prisma.prisma",
12
+ "planbcoding.vscode-react-refactor",
13
+ "yoavbls.pretty-ts-errors",
14
+ "usernamehw.errorlens"
15
+ ]
16
+ }
.vscode/settings.json ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "typescript.tsdk": "node_modules/.pnpm/[email protected]/node_modules/typescript/lib",
3
+ "typescript.enablePromptUseWorkspaceTsdk": true,
4
+ "[javascript]": {
5
+ "editor.formatOnSave": true,
6
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
7
+ },
8
+ "[typescript]": {
9
+ "editor.formatOnSave": true,
10
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
11
+ },
12
+ "[html]": {
13
+ "editor.formatOnSave": true,
14
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
15
+ },
16
+ "[scss]": {
17
+ "editor.formatOnSave": true,
18
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
19
+ },
20
+ "[css]": {
21
+ "editor.formatOnSave": true,
22
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
23
+ },
24
+ "[yaml]": {
25
+ "editor.formatOnSave": true,
26
+ "editor.defaultFormatter": "redhat.vscode-yaml"
27
+ },
28
+ "[json]": {
29
+ "editor.formatOnSave": true,
30
+ "editor.defaultFormatter": "vscode.json-language-features"
31
+ },
32
+ "cSpell.words": [
33
+ "callout",
34
+ "checkstyle",
35
+ "commitlint",
36
+ "daisyui",
37
+ "nestjs",
38
+ "nextui",
39
+ "tailwindcss",
40
+ "Trpc",
41
+ "wewe"
42
+ ]
43
+ }
apps/server/package.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "server",
3
- "version": "1.7.1",
4
  "description": "",
5
  "author": "",
6
  "private": true,
 
1
  {
2
  "name": "server",
3
+ "version": "1.9.0",
4
  "description": "",
5
  "author": "",
6
  "private": true,
apps/server/src/app.controller.ts CHANGED
@@ -1,9 +1,14 @@
1
  import { Controller, Get, Redirect, Render } from '@nestjs/common';
2
  import { AppService } from './app.service';
 
 
3
 
4
  @Controller()
5
  export class AppController {
6
- constructor(private readonly appService: AppService) {}
 
 
 
7
 
8
  @Get()
9
  getHello(): string {
@@ -23,9 +28,12 @@ export class AppController {
23
  @Render('index.hbs')
24
  dashRender() {
25
  const { originUrl: weweRssServerOriginUrl } =
26
- this.appService.getFeedConfig();
 
 
27
  return {
28
  weweRssServerOriginUrl,
 
29
  };
30
  }
31
  }
 
1
  import { Controller, Get, Redirect, Render } from '@nestjs/common';
2
  import { AppService } from './app.service';
3
+ import { ConfigService } from '@nestjs/config';
4
+ import { ConfigurationType } from './configuration';
5
 
6
  @Controller()
7
  export class AppController {
8
+ constructor(
9
+ private readonly appService: AppService,
10
+ private readonly configService: ConfigService,
11
+ ) {}
12
 
13
  @Get()
14
  getHello(): string {
 
28
  @Render('index.hbs')
29
  dashRender() {
30
  const { originUrl: weweRssServerOriginUrl } =
31
+ this.configService.get<ConfigurationType['feed']>('feed')!;
32
+ const { code } = this.configService.get<ConfigurationType['auth']>('auth')!;
33
+
34
  return {
35
  weweRssServerOriginUrl,
36
+ enabledAuthCode: !!code,
37
  };
38
  }
39
  }
apps/server/src/app.service.ts CHANGED
@@ -1,6 +1,5 @@
1
  import { Injectable } from '@nestjs/common';
2
  import { ConfigService } from '@nestjs/config';
3
- import { ConfigurationType } from './configuration';
4
 
5
  @Injectable()
6
  export class AppService {
@@ -12,8 +11,4 @@ export class AppService {
12
  </div>
13
  `;
14
  }
15
-
16
- getFeedConfig() {
17
- return this.configService.get<ConfigurationType['feed']>('feed')!;
18
- }
19
  }
 
1
  import { Injectable } from '@nestjs/common';
2
  import { ConfigService } from '@nestjs/config';
 
3
 
4
  @Injectable()
5
  export class AppService {
 
11
  </div>
12
  `;
13
  }
 
 
 
 
14
  }
apps/server/src/feeds/feeds.service.ts CHANGED
@@ -156,6 +156,7 @@ export class FeedsService {
156
  copyright: '',
157
  updated: new Date(feedInfo.updateTime * 1e3),
158
  generator: 'WeWe-RSS',
 
159
  });
160
 
161
  feed.addExtension({
@@ -163,16 +164,23 @@ export class FeedsService {
163
  objects: `WeWe-RSS`,
164
  });
165
 
 
 
 
 
166
  /**mode 高于 globalMode。如果 mode 值存在,取 mode 值*/
167
  const enableFullText =
168
  typeof mode === 'string'
169
  ? mode === 'fulltext'
170
  : globalMode === 'fulltext';
171
 
 
 
172
  const mapper = async (item) => {
173
- const { title, id, publishTime, picUrl } = item;
174
  const link = `https://mp.weixin.qq.com/s/${id}`;
175
 
 
176
  const published = new Date(publishTime * 1e3);
177
 
178
  let description = '';
@@ -188,6 +196,7 @@ export class FeedsService {
188
  description,
189
  date: published,
190
  image: picUrl,
 
191
  });
192
  };
193
 
 
156
  copyright: '',
157
  updated: new Date(feedInfo.updateTime * 1e3),
158
  generator: 'WeWe-RSS',
159
+ author: { name: feedInfo.mpName },
160
  });
161
 
162
  feed.addExtension({
 
164
  objects: `WeWe-RSS`,
165
  });
166
 
167
+ const feeds = await this.prismaService.feed.findMany({
168
+ select: { id: true, mpName: true },
169
+ });
170
+
171
  /**mode 高于 globalMode。如果 mode 值存在,取 mode 值*/
172
  const enableFullText =
173
  typeof mode === 'string'
174
  ? mode === 'fulltext'
175
  : globalMode === 'fulltext';
176
 
177
+ const showAuthor = feedInfo.id === 'all';
178
+
179
  const mapper = async (item) => {
180
+ const { title, id, publishTime, picUrl, mpId } = item;
181
  const link = `https://mp.weixin.qq.com/s/${id}`;
182
 
183
+ const mpName = feeds.find((item) => item.id === mpId)?.mpName || '-';
184
  const published = new Date(publishTime * 1e3);
185
 
186
  let description = '';
 
196
  description,
197
  date: published,
198
  image: picUrl,
199
+ author: showAuthor ? [{ name: mpName }] : undefined,
200
  });
201
  };
202
 
apps/server/src/trpc/trpc.router.ts CHANGED
@@ -22,12 +22,12 @@ export class TrpcRouter {
22
  list: this.trpcService.protectedProcedure
23
  .input(
24
  z.object({
25
- limit: z.number().min(1).max(100).nullish(),
26
  cursor: z.string().nullish(),
27
  }),
28
  )
29
  .query(async ({ input }) => {
30
- const limit = input.limit ?? 50;
31
  const { cursor } = input;
32
 
33
  const items = await this.prismaService.account.findMany({
@@ -132,12 +132,12 @@ export class TrpcRouter {
132
  list: this.trpcService.protectedProcedure
133
  .input(
134
  z.object({
135
- limit: z.number().min(1).max(100).nullish(),
136
  cursor: z.string().nullish(),
137
  }),
138
  )
139
  .query(async ({ input }) => {
140
- const limit = input.limit ?? 50;
141
  const { cursor } = input;
142
 
143
  const items = await this.prismaService.feed.findMany({
@@ -247,13 +247,13 @@ export class TrpcRouter {
247
  list: this.trpcService.protectedProcedure
248
  .input(
249
  z.object({
250
- limit: z.number().min(1).max(100).nullish(),
251
  cursor: z.string().nullish(),
252
  mpId: z.string().nullish(),
253
  }),
254
  )
255
  .query(async ({ input }) => {
256
- const limit = input.limit ?? 50;
257
  const { cursor, mpId } = input;
258
 
259
  const items = await this.prismaService.article.findMany({
@@ -401,7 +401,7 @@ export class TrpcRouter {
401
  const authCode =
402
  this.configService.get<ConfigurationType['auth']>('auth')!.code;
403
 
404
- if (req.headers.authorization !== authCode) {
405
  return {
406
  errorMsg: 'authCode不正确!',
407
  };
 
22
  list: this.trpcService.protectedProcedure
23
  .input(
24
  z.object({
25
+ limit: z.number().min(1).max(500).nullish(),
26
  cursor: z.string().nullish(),
27
  }),
28
  )
29
  .query(async ({ input }) => {
30
+ const limit = input.limit ?? 500;
31
  const { cursor } = input;
32
 
33
  const items = await this.prismaService.account.findMany({
 
132
  list: this.trpcService.protectedProcedure
133
  .input(
134
  z.object({
135
+ limit: z.number().min(1).max(500).nullish(),
136
  cursor: z.string().nullish(),
137
  }),
138
  )
139
  .query(async ({ input }) => {
140
+ const limit = input.limit ?? 500;
141
  const { cursor } = input;
142
 
143
  const items = await this.prismaService.feed.findMany({
 
247
  list: this.trpcService.protectedProcedure
248
  .input(
249
  z.object({
250
+ limit: z.number().min(1).max(500).nullish(),
251
  cursor: z.string().nullish(),
252
  mpId: z.string().nullish(),
253
  }),
254
  )
255
  .query(async ({ input }) => {
256
+ const limit = input.limit ?? 500;
257
  const { cursor, mpId } = input;
258
 
259
  const items = await this.prismaService.article.findMany({
 
401
  const authCode =
402
  this.configService.get<ConfigurationType['auth']>('auth')!.code;
403
 
404
+ if (authCode && req.headers.authorization !== authCode) {
405
  return {
406
  errorMsg: 'authCode不正确!',
407
  };
apps/web/index.html CHANGED
@@ -11,6 +11,7 @@
11
  <div id="root"></div>
12
  <script>
13
  window.__WEWE_RSS_SERVER_ORIGIN_URL__ = '{{ weweRssServerOriginUrl }}';
 
14
  </script>
15
  <script type="module" src="/src/main.tsx"></script>
16
  </body>
 
11
  <div id="root"></div>
12
  <script>
13
  window.__WEWE_RSS_SERVER_ORIGIN_URL__ = '{{ weweRssServerOriginUrl }}';
14
+ window.__WEWE_RSS_ENABLED_AUTH_CODE__ = {{ enabledAuthCode }};
15
  </script>
16
  <script type="module" src="/src/main.tsx"></script>
17
  </body>
apps/web/package.json CHANGED
@@ -1,7 +1,7 @@
1
  {
2
  "name": "web",
3
  "private": true,
4
- "version": "1.7.1",
5
  "type": "module",
6
  "scripts": {
7
  "dev": "vite",
 
1
  {
2
  "name": "web",
3
  "private": true,
4
+ "version": "1.9.0",
5
  "type": "module",
6
  "scripts": {
7
  "dev": "vite",
apps/web/src/pages/accounts/index.tsx CHANGED
@@ -25,9 +25,7 @@ import { statusMap } from '@web/constants';
25
  const AccountPage = () => {
26
  const { isOpen, onOpen, onClose, onOpenChange } = useDisclosure();
27
 
28
- const { refetch, data, isFetching } = trpc.account.list.useQuery({
29
- limit: 100,
30
- });
31
 
32
  const { mutateAsync: updateAccount } = trpc.account.edit.useMutation({});
33
 
 
25
  const AccountPage = () => {
26
  const { isOpen, onOpen, onClose, onOpenChange } = useDisclosure();
27
 
28
+ const { refetch, data, isFetching } = trpc.account.list.useQuery({});
 
 
29
 
30
  const { mutateAsync: updateAccount } = trpc.account.edit.useMutation({});
31
 
apps/web/src/pages/feeds/index.tsx CHANGED
@@ -30,9 +30,7 @@ const Feeds = () => {
30
 
31
  const { isOpen, onOpen, onOpenChange, onClose } = useDisclosure();
32
  const { refetch: refetchFeedList, data: feedData } = trpc.feed.list.useQuery(
33
- {
34
- limit: 100,
35
- },
36
  {
37
  refetchOnWindowFocus: true,
38
  },
@@ -93,6 +91,38 @@ const Feeds = () => {
93
  return feedData?.items.find((item) => item.id === currentMpId);
94
  }, [currentMpId, feedData?.items]);
95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  return (
97
  <>
98
  <div className="h-full flex justify-between">
@@ -238,15 +268,26 @@ const Feeds = () => {
238
  </Tooltip>
239
  </div>
240
  ) : (
241
- <Link
242
- size="sm"
243
- showAnchorIcon
244
- target="_blank"
245
- href={`${serverOriginUrl}/feeds/all.atom`}
246
- color="foreground"
247
- >
248
- RSS
249
- </Link>
 
 
 
 
 
 
 
 
 
 
 
250
  )}
251
  </div>
252
  <div className="p-2 overflow-y-auto">
 
30
 
31
  const { isOpen, onOpen, onOpenChange, onClose } = useDisclosure();
32
  const { refetch: refetchFeedList, data: feedData } = trpc.feed.list.useQuery(
33
+ {},
 
 
34
  {
35
  refetchOnWindowFocus: true,
36
  },
 
91
  return feedData?.items.find((item) => item.id === currentMpId);
92
  }, [currentMpId, feedData?.items]);
93
 
94
+ const handleExportOpml = async (ev) => {
95
+ ev.preventDefault();
96
+ ev.stopPropagation();
97
+ if (!feedData?.items?.length) {
98
+ console.warn('没有订阅源');
99
+ return;
100
+ }
101
+
102
+ let opmlContent = `<?xml version="1.0" encoding="UTF-8"?>
103
+ <opml version="2.0">
104
+ <head>
105
+ <title>WeWeRSS 所有订阅源</title>
106
+ </head>
107
+ <body>
108
+ `;
109
+
110
+ feedData?.items.forEach((sub) => {
111
+ opmlContent += ` <outline text="${sub.mpName}" type="rss" xmlUrl="${window.location.origin}/feeds/${sub.id}.atom" htmlUrl="${window.location.origin}/feeds/${sub.id}.atom"/>\n`;
112
+ });
113
+
114
+ opmlContent += ` </body>
115
+ </opml>`;
116
+
117
+ const blob = new Blob([opmlContent], { type: 'text/xml;charset=utf-8;' });
118
+ const link = document.createElement('a');
119
+ link.href = URL.createObjectURL(blob);
120
+ link.download = 'WeWeRSS-All.opml';
121
+ document.body.appendChild(link);
122
+ link.click();
123
+ document.body.removeChild(link);
124
+ };
125
+
126
  return (
127
  <>
128
  <div className="h-full flex justify-between">
 
268
  </Tooltip>
269
  </div>
270
  ) : (
271
+ <div className="flex gap-2">
272
+ <Link
273
+ href="#"
274
+ color="foreground"
275
+ onClick={handleExportOpml}
276
+ size="sm"
277
+ >
278
+ 导出OPML
279
+ </Link>
280
+ <Divider orientation="vertical" />
281
+ <Link
282
+ size="sm"
283
+ showAnchorIcon
284
+ target="_blank"
285
+ href={`${serverOriginUrl}/feeds/all.atom`}
286
+ color="foreground"
287
+ >
288
+ RSS
289
+ </Link>
290
+ </div>
291
  )}
292
  </div>
293
  <div className="p-2 overflow-y-auto">
apps/web/src/provider/trpc.tsx CHANGED
@@ -5,13 +5,19 @@ import { useState } from 'react';
5
  import { toast } from 'sonner';
6
  import { isTRPCClientError, trpc } from '../utils/trpc';
7
  import { getAuthCode, setAuthCode } from '../utils/auth';
8
- import { serverOriginUrl } from '../utils/env';
9
 
10
  export const TrpcProvider: React.FC<{ children: React.ReactNode }> = ({
11
  children,
12
  }) => {
13
  const navigate = useNavigate();
14
 
 
 
 
 
 
 
15
  const [queryClient] = useState(
16
  () =>
17
  new QueryClient({
@@ -38,8 +44,7 @@ export const TrpcProvider: React.FC<{ children: React.ReactNode }> = ({
38
  description: error.message,
39
  });
40
 
41
- setAuthCode('');
42
- navigate('/login');
43
  } else {
44
  toast.error('请求失败!', {
45
  description: error.message,
@@ -56,8 +61,7 @@ export const TrpcProvider: React.FC<{ children: React.ReactNode }> = ({
56
  toast.error('无权限', {
57
  description: error.message,
58
  });
59
- setAuthCode(null);
60
- navigate('/login');
61
  } else {
62
  toast.error('请求失败!', {
63
  description: error.message,
@@ -82,9 +86,10 @@ export const TrpcProvider: React.FC<{ children: React.ReactNode }> = ({
82
  const token = getAuthCode();
83
 
84
  if (!token) {
85
- navigate('/login');
86
  return {};
87
  }
 
88
  return token
89
  ? {
90
  Authorization: `${token}`,
 
5
  import { toast } from 'sonner';
6
  import { isTRPCClientError, trpc } from '../utils/trpc';
7
  import { getAuthCode, setAuthCode } from '../utils/auth';
8
+ import { enabledAuthCode, serverOriginUrl } from '../utils/env';
9
 
10
  export const TrpcProvider: React.FC<{ children: React.ReactNode }> = ({
11
  children,
12
  }) => {
13
  const navigate = useNavigate();
14
 
15
+ const handleNoAuth = () => {
16
+ if (enabledAuthCode) {
17
+ setAuthCode('');
18
+ navigate('/login');
19
+ }
20
+ };
21
  const [queryClient] = useState(
22
  () =>
23
  new QueryClient({
 
44
  description: error.message,
45
  });
46
 
47
+ handleNoAuth();
 
48
  } else {
49
  toast.error('请求失败!', {
50
  description: error.message,
 
61
  toast.error('无权限', {
62
  description: error.message,
63
  });
64
+ handleNoAuth();
 
65
  } else {
66
  toast.error('请求失败!', {
67
  description: error.message,
 
86
  const token = getAuthCode();
87
 
88
  if (!token) {
89
+ handleNoAuth();
90
  return {};
91
  }
92
+
93
  return token
94
  ? {
95
  Authorization: `${token}`,
apps/web/src/utils/env.ts CHANGED
@@ -5,3 +5,6 @@ export const serverOriginUrl = isProd
5
  : import.meta.env.VITE_SERVER_ORIGIN_URL;
6
 
7
  export const appVersion = __APP_VERSION__;
 
 
 
 
5
  : import.meta.env.VITE_SERVER_ORIGIN_URL;
6
 
7
  export const appVersion = __APP_VERSION__;
8
+
9
+ export const enabledAuthCode =
10
+ window.__WEWE_RSS_ENABLED_AUTH_CODE__ === false ? false : true;
apps/web/src/vite-env.d.ts CHANGED
@@ -7,6 +7,7 @@ interface ImportMetaEnv {
7
 
8
  interface Window {
9
  __WEWE_RSS_SERVER_ORIGIN_URL__?: string;
 
10
  }
11
 
12
  declare const __APP_VERSION__: string;
 
7
 
8
  interface Window {
9
  __WEWE_RSS_SERVER_ORIGIN_URL__?: string;
10
+ __WEWE_RSS_ENABLED_AUTH_CODE__?: boolean;
11
  }
12
 
13
  declare const __APP_VERSION__: string;
package.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "name": "wewe-rss",
3
- "version": "1.7.1",
4
  "private": true,
5
  "author": "cooderl <[email protected]>",
6
  "description": "",
 
1
  {
2
  "name": "wewe-rss",
3
+ "version": "1.9.0",
4
  "private": true,
5
  "author": "cooderl <[email protected]>",
6
  "description": "",