@lobb-js/lobb-ext-auth 0.1.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.zed/settings.json +22 -0
- package/deno.json +18 -0
- package/deno.lock +968 -0
- package/lobb/lobb.ts +108 -0
- package/lobb/src/collections/activityFeed.ts +53 -0
- package/lobb/src/collections/collections.ts +44 -0
- package/lobb/src/collections/sessions.ts +34 -0
- package/lobb/src/collections/users.ts +44 -0
- package/lobb/src/config/config.ts +11 -0
- package/lobb/src/config/extensionConfigSchema.ts +47 -0
- package/lobb/src/config/permissionsAction/create.ts +20 -0
- package/lobb/src/config/permissionsAction/delete.ts +3 -0
- package/lobb/src/config/permissionsAction/read.ts +10 -0
- package/lobb/src/config/permissionsAction/update.ts +20 -0
- package/lobb/src/database/init.ts +51 -0
- package/lobb/src/database/migrations.ts +56 -0
- package/lobb/src/database/utils.ts +35 -0
- package/lobb/src/extension.json +1 -0
- package/lobb/src/meta/meta.ts +11 -0
- package/lobb/src/mod.ts +27 -0
- package/lobb/src/openapi.ts +469 -0
- package/lobb/src/utils.ts +17 -0
- package/lobb/src/workflows/baseWorkflow.ts +159 -0
- package/lobb/src/workflows/hashHandlerWorkflows.ts +29 -0
- package/lobb/src/workflows/index.ts +28 -0
- package/lobb/src/workflows/meAliasWorkflows.ts +48 -0
- package/lobb/src/workflows/policiesWorkflows.ts +228 -0
- package/lobb/src/workflows/utils.ts +297 -0
- package/lobb/tests/collections/extend_users_collection.test.ts +63 -0
- package/lobb/tests/configs/auth.ts +72 -0
- package/lobb/tests/configs/auth_no_roles.ts +64 -0
- package/lobb/tests/configs/auth_public_full_access.ts +68 -0
- package/lobb/tests/configs/auth_with_different_admin_creds.ts +80 -0
- package/lobb/tests/configs/auth_with_extend_users.ts +80 -0
- package/lobb/tests/configs/auth_with_refresh_token.ts +85 -0
- package/lobb/tests/configs/auth_with_short_access_token_only.ts +94 -0
- package/lobb/tests/configs/auth_with_short_time_refresh_token.ts +85 -0
- package/lobb/tests/configs/social_blog.ts +155 -0
- package/lobb/tests/controllers/change_password.test.ts +114 -0
- package/lobb/tests/controllers/dashboardAccessRoles.test.ts +29 -0
- package/lobb/tests/controllers/login.test.ts +103 -0
- package/lobb/tests/controllers/logout.test.ts +88 -0
- package/lobb/tests/controllers/me.test.ts +275 -0
- package/lobb/tests/controllers/register.test.ts +46 -0
- package/lobb/tests/database/db.test.ts +68 -0
- package/lobb/tests/database/differentAdminCreds.test.ts +50 -0
- package/lobb/tests/middlewares/adminAuthGuard.test.ts +160 -0
- package/lobb/tests/middlewares/publicAllowBasic.test.ts +142 -0
- package/lobb/tests/middlewares/publicPreventBasic.test.ts +111 -0
- package/lobb/tests/socialBlog.test.ts +260 -0
- package/lobb/tests/utils/addArticles.ts +26 -0
- package/lobb/tests/utils/addSocialBlogArticles.ts +60 -0
- package/lobb/tests/utils/data/articles.ts +65 -0
- package/lobb/tests/utils/data/socialBlogArticles.ts +56 -0
- package/package.json +32 -0
- package/studio/.env +1 -0
- package/studio/README.md +1 -0
- package/studio/index.html +13 -0
- package/studio/postcss.config.js +6 -0
- package/studio/public/vite.svg +1 -0
- package/studio/src/auth.ts +57 -0
- package/studio/src/index.ts +54 -0
- package/studio/src/main.ts +12 -0
- package/studio/src/onStartup.ts +25 -0
- package/studio/src/pages/loginPage/index.svelte +64 -0
- package/studio/src/pages/settings/index.svelte +53 -0
- package/studio/src/pages/settings/pages/activityFeed.svelte +21 -0
- package/studio/src/pages/settings/pages/rolesAndPermissions.svelte +21 -0
- package/studio/src/pages/settings/pages/users.svelte +21 -0
- package/studio/src/pages/userSettings/components/account.svelte +106 -0
- package/studio/src/pages/userSettings/components/profile.svelte +87 -0
- package/studio/src/pages/userSettings/index.svelte +48 -0
- package/studio/svelte.config.js +8 -0
- package/studio/tailwind.config.ts +93 -0
- package/studio/tsconfig.app.json +22 -0
- package/studio/tsconfig.json +7 -0
- package/studio/tsconfig.node.json +26 -0
- package/studio/vite.config.ts +14 -0
- package/todo.md +37 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { Lobb } from "@lobb/core";
|
|
2
|
+
import { assertEquals, assertObjectMatch } from "@std/assert";
|
|
3
|
+
import { afterAll, beforeAll, describe, it } from "@std/testing/bdd";
|
|
4
|
+
import {
|
|
5
|
+
createArticles,
|
|
6
|
+
removeArticles,
|
|
7
|
+
} from "./utils/addSocialBlogArticles.ts";
|
|
8
|
+
import { socialBlogConfig } from "./configs/social_blog.ts";
|
|
9
|
+
|
|
10
|
+
describe("Social Blog Auth", () => {
|
|
11
|
+
let lobb: Lobb;
|
|
12
|
+
let articlesIds: string[];
|
|
13
|
+
let newUserId: string;
|
|
14
|
+
|
|
15
|
+
beforeAll(async () => {
|
|
16
|
+
lobb = await Lobb.init(socialBlogConfig);
|
|
17
|
+
articlesIds = await createArticles(lobb);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterAll(async () => {
|
|
21
|
+
await removeArticles(lobb);
|
|
22
|
+
await lobb.close();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("should return only public status articles for public users", async () => {
|
|
26
|
+
const response = await fetch(
|
|
27
|
+
"http://127.0.0.1:3001/api/collections/articles?sort=id",
|
|
28
|
+
{
|
|
29
|
+
method: "GET",
|
|
30
|
+
},
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const result = await response.json();
|
|
34
|
+
const titles = result.data.map((article: any) => article.title);
|
|
35
|
+
|
|
36
|
+
assertEquals(
|
|
37
|
+
titles,
|
|
38
|
+
[
|
|
39
|
+
"The Future of AI: Trends Shaping Tomorrow's Technology",
|
|
40
|
+
"Mental Health in the Digital Age: Navigating the New Challenges",
|
|
41
|
+
"The Role of 5G in Revolutionizing Smart Cities",
|
|
42
|
+
],
|
|
43
|
+
);
|
|
44
|
+
assertEquals(response.status, 200);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("returns only public articles or the private and public articles that the user owns", async () => {
|
|
48
|
+
// login with the doe user
|
|
49
|
+
const headers = new Headers();
|
|
50
|
+
|
|
51
|
+
const loginResponse = await fetch(
|
|
52
|
+
"http://127.0.0.1:3001/api/collections/auth_sessions",
|
|
53
|
+
{
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers: {
|
|
56
|
+
"Content-Type": "application/json",
|
|
57
|
+
},
|
|
58
|
+
body: JSON.stringify({
|
|
59
|
+
data: {
|
|
60
|
+
email: "doe@gmail.com",
|
|
61
|
+
password: "123456",
|
|
62
|
+
},
|
|
63
|
+
}),
|
|
64
|
+
},
|
|
65
|
+
);
|
|
66
|
+
const loginData = await loginResponse.json();
|
|
67
|
+
|
|
68
|
+
headers.append(
|
|
69
|
+
"Authorization",
|
|
70
|
+
`Bearer ${loginData.data.access_token.token}`,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// get articles with the doe user
|
|
74
|
+
const response = await fetch(
|
|
75
|
+
"http://127.0.0.1:3001/api/collections/articles?sort=id",
|
|
76
|
+
{
|
|
77
|
+
method: "GET",
|
|
78
|
+
headers: headers,
|
|
79
|
+
},
|
|
80
|
+
);
|
|
81
|
+
const result = await response.json();
|
|
82
|
+
|
|
83
|
+
const titles = result.data.map((article: any) => article.title);
|
|
84
|
+
|
|
85
|
+
assertEquals(
|
|
86
|
+
titles,
|
|
87
|
+
[
|
|
88
|
+
"The Future of AI: Trends Shaping Tomorrow's Technology",
|
|
89
|
+
"Mental Health in the Digital Age: Navigating the New Challenges",
|
|
90
|
+
"Sustainable Fashion: How the Industry is Going Green",
|
|
91
|
+
"The Role of 5G in Revolutionizing Smart Cities",
|
|
92
|
+
"Digital Marketing in 2024: Emerging Strategies for Success",
|
|
93
|
+
"The Future of Renewable Energy: Innovations Driving a Clean Energy Revolution",
|
|
94
|
+
],
|
|
95
|
+
);
|
|
96
|
+
assertEquals(response.status, 200);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("should prevent public users from creating users with a role other than the author role", async () => {
|
|
100
|
+
// get articles with the doe user
|
|
101
|
+
const response = await fetch(
|
|
102
|
+
"http://127.0.0.1:3001/api/collections/auth_users",
|
|
103
|
+
{
|
|
104
|
+
method: "POST",
|
|
105
|
+
body: JSON.stringify({
|
|
106
|
+
data: {
|
|
107
|
+
email: "new_user@gmail.com",
|
|
108
|
+
password: "123456",
|
|
109
|
+
role: "admin",
|
|
110
|
+
},
|
|
111
|
+
}),
|
|
112
|
+
},
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
const result = await response.json();
|
|
116
|
+
|
|
117
|
+
assertEquals(response.status, 403);
|
|
118
|
+
assertEquals(
|
|
119
|
+
result,
|
|
120
|
+
{
|
|
121
|
+
status: 403,
|
|
122
|
+
code: "FORBIDDEN",
|
|
123
|
+
message: "You do not have permission to perform this action.",
|
|
124
|
+
},
|
|
125
|
+
);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("should allow public users to create users with the author role", async () => {
|
|
129
|
+
// get articles with the doe user
|
|
130
|
+
const response = await fetch(
|
|
131
|
+
"http://127.0.0.1:3001/api/collections/auth_users",
|
|
132
|
+
{
|
|
133
|
+
method: "POST",
|
|
134
|
+
body: JSON.stringify({
|
|
135
|
+
data: {
|
|
136
|
+
email: "new_user@gmail.com",
|
|
137
|
+
password: "123456",
|
|
138
|
+
role: "author",
|
|
139
|
+
},
|
|
140
|
+
}),
|
|
141
|
+
},
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const result = await response.json();
|
|
145
|
+
|
|
146
|
+
assertEquals(response.status, 201);
|
|
147
|
+
assertObjectMatch(
|
|
148
|
+
result.data,
|
|
149
|
+
{
|
|
150
|
+
email: "new_user@gmail.com",
|
|
151
|
+
},
|
|
152
|
+
);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("should fill the author_id of the article automatically with the logged in user_id", async () => {
|
|
156
|
+
const headers = new Headers();
|
|
157
|
+
const loginResponse = await fetch(
|
|
158
|
+
"http://127.0.0.1:3001/api/collections/auth_sessions",
|
|
159
|
+
{
|
|
160
|
+
method: "POST",
|
|
161
|
+
body: JSON.stringify({
|
|
162
|
+
data: {
|
|
163
|
+
email: "new_user@gmail.com",
|
|
164
|
+
password: "123456",
|
|
165
|
+
},
|
|
166
|
+
}),
|
|
167
|
+
},
|
|
168
|
+
);
|
|
169
|
+
const loginData = await loginResponse.json();
|
|
170
|
+
newUserId = loginData.data.user.id;
|
|
171
|
+
headers.append(
|
|
172
|
+
"Authorization",
|
|
173
|
+
`Bearer ${loginData.data.access_token.token}`,
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// create an article
|
|
177
|
+
const response = await fetch(
|
|
178
|
+
"http://127.0.0.1:3001/api/collections/articles",
|
|
179
|
+
{
|
|
180
|
+
headers: headers,
|
|
181
|
+
method: "POST",
|
|
182
|
+
body: JSON.stringify({
|
|
183
|
+
data: {
|
|
184
|
+
title: "new article created by the new user",
|
|
185
|
+
body: "test the new body",
|
|
186
|
+
},
|
|
187
|
+
}),
|
|
188
|
+
},
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const result = await response.json();
|
|
192
|
+
|
|
193
|
+
assertEquals(response.status, 201);
|
|
194
|
+
assertObjectMatch(
|
|
195
|
+
result.data,
|
|
196
|
+
{
|
|
197
|
+
author_id: newUserId,
|
|
198
|
+
title: "new article created by the new user",
|
|
199
|
+
body: "test the new body",
|
|
200
|
+
description: null,
|
|
201
|
+
image: null,
|
|
202
|
+
status: "private",
|
|
203
|
+
},
|
|
204
|
+
);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("should hide the password of the users from the returned responses of findOne operations", async () => {
|
|
208
|
+
// create an article
|
|
209
|
+
const response = await fetch(
|
|
210
|
+
"http://127.0.0.1:3001/api/collections/auth_users/" + newUserId,
|
|
211
|
+
{
|
|
212
|
+
method: "Get",
|
|
213
|
+
},
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
const result = await response.json();
|
|
217
|
+
|
|
218
|
+
assertEquals(response.status, 200);
|
|
219
|
+
assertEquals(
|
|
220
|
+
Object.keys(result.data).includes("password"),
|
|
221
|
+
false,
|
|
222
|
+
);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("should hide the password of the users from the returned responses of findAll operations", async () => {
|
|
226
|
+
const response = await fetch(
|
|
227
|
+
"http://127.0.0.1:3001/api/collections/auth_users",
|
|
228
|
+
{
|
|
229
|
+
method: "Get",
|
|
230
|
+
},
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
const result = await response.json();
|
|
234
|
+
|
|
235
|
+
assertEquals(
|
|
236
|
+
Object.keys(result.data).includes("password"),
|
|
237
|
+
false,
|
|
238
|
+
);
|
|
239
|
+
assertEquals(response.status, 200);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("should prevent public users from getting admin role users", async () => {
|
|
243
|
+
const response = await fetch(
|
|
244
|
+
"http://127.0.0.1:3001/api/collections/auth_users",
|
|
245
|
+
{
|
|
246
|
+
method: "Get",
|
|
247
|
+
},
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
const result = await response.json();
|
|
251
|
+
|
|
252
|
+
const adminUsers = result.data.filter((user: any) => user.role === "admin");
|
|
253
|
+
|
|
254
|
+
assertEquals(
|
|
255
|
+
adminUsers.length,
|
|
256
|
+
0,
|
|
257
|
+
);
|
|
258
|
+
assertEquals(response.status, 200);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Lobb } from "@lobb/core";
|
|
2
|
+
import { articles } from "../utils/data/articles.ts";
|
|
3
|
+
|
|
4
|
+
export async function createArticles(lobb: Lobb) {
|
|
5
|
+
const collectionService = lobb.utils.getCollectionService({
|
|
6
|
+
collectionName: "articles",
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const createdArticles: any[] = [];
|
|
10
|
+
for (let index = 0; index < articles.length; index++) {
|
|
11
|
+
const article = articles[index];
|
|
12
|
+
const createdArticle = (await collectionService.createOne({
|
|
13
|
+
data: article,
|
|
14
|
+
})).data;
|
|
15
|
+
createdArticles.push(createdArticle);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return createdArticles.map((article) => article.id);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function removeArticles(lobb: Lobb) {
|
|
22
|
+
const collectionService = lobb.utils.getCollectionService({
|
|
23
|
+
collectionName: "articles",
|
|
24
|
+
});
|
|
25
|
+
await collectionService.deleteMany({});
|
|
26
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Lobb } from "@lobb/core";
|
|
2
|
+
import { articles } from "./data/socialBlogArticles.ts";
|
|
3
|
+
|
|
4
|
+
export async function createArticles(lobb: Lobb) {
|
|
5
|
+
// clean collections
|
|
6
|
+
await removeArticles(lobb);
|
|
7
|
+
|
|
8
|
+
// create the owner user
|
|
9
|
+
const usersService = lobb.utils.getCollectionService({
|
|
10
|
+
collectionName: "auth_users",
|
|
11
|
+
});
|
|
12
|
+
const user = (await usersService.createOne({
|
|
13
|
+
data: {
|
|
14
|
+
email: "john@gmail.com",
|
|
15
|
+
password: "123456",
|
|
16
|
+
role: "author",
|
|
17
|
+
},
|
|
18
|
+
})).data;
|
|
19
|
+
const user2 = (await usersService.createOne({
|
|
20
|
+
data: {
|
|
21
|
+
email: "doe@gmail.com",
|
|
22
|
+
password: "123456",
|
|
23
|
+
role: "author",
|
|
24
|
+
},
|
|
25
|
+
})).data;
|
|
26
|
+
|
|
27
|
+
// create the articles
|
|
28
|
+
const collectionService = lobb.utils.getCollectionService({
|
|
29
|
+
collectionName: "articles",
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const createdArticles: any[] = [];
|
|
33
|
+
for (let index = 0; index < articles.length; index++) {
|
|
34
|
+
const article: any = articles[index];
|
|
35
|
+
article["author_id"] = index > (articles.length / 2) ? user2.id : user.id;
|
|
36
|
+
const createdArticle = (await collectionService.createOne({
|
|
37
|
+
data: article,
|
|
38
|
+
})).data;
|
|
39
|
+
createdArticles.push(createdArticle);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return createdArticles.map((article) => article.id);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function removeArticles(lobb: Lobb) {
|
|
46
|
+
const collectionService = lobb.utils.getCollectionService({
|
|
47
|
+
collectionName: "articles",
|
|
48
|
+
});
|
|
49
|
+
await collectionService.deleteMany({
|
|
50
|
+
filter: {},
|
|
51
|
+
force: true,
|
|
52
|
+
});
|
|
53
|
+
const usersService = lobb.utils.getCollectionService({
|
|
54
|
+
collectionName: "auth_users",
|
|
55
|
+
});
|
|
56
|
+
await usersService.deleteMany({
|
|
57
|
+
filter: {},
|
|
58
|
+
force: true,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export const articles = [
|
|
2
|
+
{
|
|
3
|
+
title: "The Future of AI: Trends Shaping Tomorrow's Technology",
|
|
4
|
+
body:
|
|
5
|
+
"Explore how artificial intelligence is evolving, from machine learning innovations to ethical challenges in AI governance. This article delves into the transformative potential AI holds for industries like healthcare, finance, and automation.",
|
|
6
|
+
number_of_likes: 454,
|
|
7
|
+
published: null,
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
title: "Climate Change and Its Impact on Global Food Security",
|
|
11
|
+
body:
|
|
12
|
+
"This article examines the effect of climate change on agriculture and global food production. It covers rising temperatures, changing weather patterns, and their implications for food supply chains, emphasizing the need for sustainable farming practices Wow.",
|
|
13
|
+
number_of_likes: 1212,
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
title: "The Rise of Remote Work: Is the Office Dead?",
|
|
17
|
+
body:
|
|
18
|
+
"A comprehensive analysis of How remote work has redefined the modern workplace post-pandemic. It discusses benefits and challenges for both employers and employees, and whether traditional office spaces will continue to exist in the future.",
|
|
19
|
+
number_of_likes: 9848,
|
|
20
|
+
published: true,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
title: "Blockchain Beyond Cryptocurrency: Practical Applications in 2024",
|
|
24
|
+
body:
|
|
25
|
+
"Blockchain technology extends far beyond Bitcoin and digital currencies. This article explains its real-world uses in supply chain management, healthcare, and secure voting systems, highlighting successful implementations and ongoing experiments.",
|
|
26
|
+
number_of_likes: 10,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
title: "Mental Health in the Digital Age: Navigating the New Challenges",
|
|
30
|
+
body:
|
|
31
|
+
"With increasing screen time and social media usage, mental health issues have taken new forms. This article addresses the growing concerns around digital addiction, online anxiety, and the role of tech companies in promoting well-being wow.",
|
|
32
|
+
number_of_likes: 5,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
title: "Understanding Quantum Computing: The Next Tech Revolution",
|
|
36
|
+
body:
|
|
37
|
+
"Quantum computing promises to solve problems too complex for classical computers. This article breaks down the fundamentals of quantum technology, its current state, and its future potential across industries like pharmaceuticals, logistics, and cybersecurity.",
|
|
38
|
+
number_of_likes: 156,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
title: "Sustainable Fashion: How the Industry is Going Green",
|
|
42
|
+
body:
|
|
43
|
+
"With environmental consciousness on the rise, the fashion industry is pivoting toward sustainability. This article looks at eco-friendly materials, ethical manufacturing processes, and how major brands are embracing the green movement wow.",
|
|
44
|
+
number_of_likes: 89,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
title: "The Role of 5G in Revolutionizing Smart Cities",
|
|
48
|
+
body:
|
|
49
|
+
"As 5G networks roll out globally, smart cities are becoming a reality. This wow article covers how 5G technology wow will enable real-time data sharing, improve urban infrastructure, wow and enhance public services through IoT devices and smart sensors.",
|
|
50
|
+
number_of_likes: 15,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
title: "Digital Marketing in 2024: Emerging Strategies for Success",
|
|
54
|
+
body:
|
|
55
|
+
"The landscape of digital marketing is rapidly changing with the rise of AI, personalized experiences, and social commerce. This article outlines the most promising strategies to stay ahead in 2024, from leveraging data analytics to mastering content creation wow.",
|
|
56
|
+
number_of_likes: 87,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
title:
|
|
60
|
+
"The Future of Renewable Energy: Innovations Driving a Clean Energy Revolution",
|
|
61
|
+
body:
|
|
62
|
+
"As the world shifts toward green energy, this article highlights wow the latest innovations in solar, wind, and hydropower technologies. It also discusses policy trends, wow global investment in renewables, wow and the challenges in achieving net-zero emissions by 2050 wow.",
|
|
63
|
+
number_of_likes: 48,
|
|
64
|
+
},
|
|
65
|
+
];
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export const articles = [
|
|
2
|
+
{
|
|
3
|
+
title: "The Future of AI: Trends Shaping Tomorrow's Technology",
|
|
4
|
+
body:
|
|
5
|
+
"Explore how artificial intelligence is evolving, from machine learning innovations to ethical challenges in AI governance. This article delves into the transformative potential AI holds for industries like healthcare, finance, and automation.",
|
|
6
|
+
status: "public",
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
title: "Climate Change and Its Impact on Global Food Security",
|
|
10
|
+
body:
|
|
11
|
+
"This article examines the effect of climate change on agriculture and global food production. It covers rising temperatures, changing weather patterns, and their implications for food supply chains, emphasizing the need for sustainable farming practices Wow.",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
title: "The Rise of Remote Work: Is the Office Dead?",
|
|
15
|
+
body:
|
|
16
|
+
"A comprehensive analysis of How remote work has redefined the modern workplace post-pandemic. It discusses benefits and challenges for both employers and employees, and whether traditional office spaces will continue to exist in the future.",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
title: "Blockchain Beyond Cryptocurrency: Practical Applications in 2024",
|
|
20
|
+
body:
|
|
21
|
+
"Blockchain technology extends far beyond Bitcoin and digital currencies. This article explains its real-world uses in supply chain management, healthcare, and secure voting systems, highlighting successful implementations and ongoing experiments.",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
title: "Mental Health in the Digital Age: Navigating the New Challenges",
|
|
25
|
+
body:
|
|
26
|
+
"With increasing screen time and social media usage, mental health issues have taken new forms. This article addresses the growing concerns around digital addiction, online anxiety, and the role of tech companies in promoting well-being wow.",
|
|
27
|
+
status: "public",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
title: "Understanding Quantum Computing: The Next Tech Revolution",
|
|
31
|
+
body:
|
|
32
|
+
"Quantum computing promises to solve problems too complex for classical computers. This article breaks down the fundamentals of quantum technology, its current state, and its future potential across industries like pharmaceuticals, logistics, and cybersecurity.",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
title: "Sustainable Fashion: How the Industry is Going Green",
|
|
36
|
+
body:
|
|
37
|
+
"With environmental consciousness on the rise, the fashion industry is pivoting toward sustainability. This article looks at eco-friendly materials, ethical manufacturing processes, and how major brands are embracing the green movement wow.",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
title: "The Role of 5G in Revolutionizing Smart Cities",
|
|
41
|
+
body:
|
|
42
|
+
"As 5G networks roll out globally, smart cities are becoming a reality. This wow article covers how 5G technology wow will enable real-time data sharing, improve urban infrastructure, wow and enhance public services through IoT devices and smart sensors.",
|
|
43
|
+
status: "public",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
title: "Digital Marketing in 2024: Emerging Strategies for Success",
|
|
47
|
+
body:
|
|
48
|
+
"The landscape of digital marketing is rapidly changing with the rise of AI, personalized experiences, and social commerce. This article outlines the most promising strategies to stay ahead in 2024, from leveraging data analytics to mastering content creation wow.",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
title:
|
|
52
|
+
"The Future of Renewable Energy: Innovations Driving a Clean Energy Revolution",
|
|
53
|
+
body:
|
|
54
|
+
"As the world shifts toward green energy, this article highlights wow the latest innovations in solar, wind, and hydropower technologies. It also discusses policy trends, wow global investment in renewables, wow and the challenges in achieving net-zero emissions by 2050 wow.",
|
|
55
|
+
},
|
|
56
|
+
];
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lobb-js/lobb-ext-auth",
|
|
3
|
+
"version": "0.1.58",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": "./studio/src/index.ts"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"dev": "cd studio && vite",
|
|
10
|
+
"build": "cd studio && vite build",
|
|
11
|
+
"preview": "cd studio && vite preview",
|
|
12
|
+
"check": "cd studio && svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json",
|
|
13
|
+
"publish": "npm publish --access public"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@ai-sdk/openai": "^3.0.21",
|
|
17
|
+
"@lobb-js/studio": "0.1.31",
|
|
18
|
+
"ai": "^6.0.59"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@sveltejs/vite-plugin-svelte": "6.2.1",
|
|
22
|
+
"@tsconfig/svelte": "^5.0.6",
|
|
23
|
+
"@types/node": "^24.10.1",
|
|
24
|
+
"autoprefixer": "^10.4.23",
|
|
25
|
+
"svelte": "^5.43.8",
|
|
26
|
+
"svelte-check": "^4.3.4",
|
|
27
|
+
"tailwindcss": "^3.4.19",
|
|
28
|
+
"tailwindcss-animate": "^1.0.7",
|
|
29
|
+
"typescript": "~5.9.3",
|
|
30
|
+
"vite": "6.3.3"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/studio/.env
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
NGROK_AUTHTOKEN=2NBFGwIM5SqpEcyRnR0k2Kh6Dm4_6a69urL1RTUc6zqfqaZ4R
|
package/studio/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# instagram_api_integration
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Lobb Studio</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/src/main.ts"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { ExtensionUtils } from "../extension.types";
|
|
2
|
+
|
|
3
|
+
interface LoginPayload {
|
|
4
|
+
email: string;
|
|
5
|
+
password: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class Auth {
|
|
9
|
+
private utils: ExtensionUtils;
|
|
10
|
+
|
|
11
|
+
constructor(utils: ExtensionUtils) {
|
|
12
|
+
this.utils = utils;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public getSession() {
|
|
16
|
+
const lobbSession = localStorage.getItem("lobb_session");
|
|
17
|
+
if (lobbSession) {
|
|
18
|
+
const parsedLobbSession = JSON.parse(lobbSession);
|
|
19
|
+
this.utils.lobb.setHeaders({
|
|
20
|
+
Authorization: `Bearer ${parsedLobbSession.access_token.token}`,
|
|
21
|
+
});
|
|
22
|
+
return parsedLobbSession;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public async login(payload: LoginPayload) {
|
|
27
|
+
const response = await this.utils.lobb.request({
|
|
28
|
+
method: "POST",
|
|
29
|
+
route: "/api/collections/auth_sessions",
|
|
30
|
+
payload: {
|
|
31
|
+
data: payload,
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
if (response.status >= 400) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const result = await response.json();
|
|
39
|
+
const session = result.data;
|
|
40
|
+
localStorage.setItem("lobb_session", JSON.stringify(session));
|
|
41
|
+
|
|
42
|
+
this.utils.ctx.extensions.auth.session = session;
|
|
43
|
+
this.utils.lobb.setHeaders({
|
|
44
|
+
Authorization: `Bearer ${session.access_token.token}`,
|
|
45
|
+
});
|
|
46
|
+
this.utils.location.navigate("/");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public async logout() {
|
|
50
|
+
await this.utils.lobb.request({
|
|
51
|
+
method: "DELETE",
|
|
52
|
+
route: "/api/extensions/auth/logout",
|
|
53
|
+
});
|
|
54
|
+
localStorage.removeItem("lobb_session");
|
|
55
|
+
this.utils.location.navigate("/extensions/auth/login_page");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Extension, ExtensionUtils } from "../extension.types";
|
|
2
|
+
import { Auth } from "./auth";
|
|
3
|
+
import { onStartup } from "./onStartup";
|
|
4
|
+
import LoginPage from "./pages/loginPage/index.svelte";
|
|
5
|
+
import UserSettings from "./pages/userSettings/index.svelte";
|
|
6
|
+
import Settings from "./pages/settings/index.svelte";
|
|
7
|
+
|
|
8
|
+
// TODO we should export the extension object directly without a function at all. because we dont set configuration in here
|
|
9
|
+
export function extension(utils: ExtensionUtils): Extension {
|
|
10
|
+
return {
|
|
11
|
+
name: "auth",
|
|
12
|
+
onStartup: onStartup,
|
|
13
|
+
components: {
|
|
14
|
+
"pages.login_page": LoginPage,
|
|
15
|
+
"pages.user_settings": UserSettings,
|
|
16
|
+
"pages.settings": Settings,
|
|
17
|
+
},
|
|
18
|
+
dashboardNavs: {
|
|
19
|
+
middle: [
|
|
20
|
+
{
|
|
21
|
+
label: "Auth",
|
|
22
|
+
icon: utils.components.Icons.Key,
|
|
23
|
+
href: "/extensions/auth/settings/users",
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
bottom: [
|
|
27
|
+
{
|
|
28
|
+
label: "My User",
|
|
29
|
+
icon: utils.components.Icons.User,
|
|
30
|
+
onclick: () => {
|
|
31
|
+
utils.location.navigate("/extensions/auth/user_settings");
|
|
32
|
+
},
|
|
33
|
+
navs: [
|
|
34
|
+
{
|
|
35
|
+
label: "User Settings",
|
|
36
|
+
icon: utils.components.Icons.Settings,
|
|
37
|
+
onclick: () => {
|
|
38
|
+
utils.location.navigate("/extensions/auth/user_settings");
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
label: "Logout",
|
|
43
|
+
icon: utils.components.Icons.LogOut,
|
|
44
|
+
onclick: () => {
|
|
45
|
+
const auth = new Auth(utils);
|
|
46
|
+
auth.logout();
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { mount } from "svelte";
|
|
2
|
+
import Studio from "@lobb-js/studio";
|
|
3
|
+
import { extension } from "./index.ts";
|
|
4
|
+
|
|
5
|
+
const app = mount(Studio, {
|
|
6
|
+
target: document.getElementById("app")!,
|
|
7
|
+
props: {
|
|
8
|
+
extensions: [extension],
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export default app;
|