create-warlock 1.0.0

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.
Files changed (169) hide show
  1. package/README.md +29 -0
  2. package/cjs/commands/create-new-app/get-app-path.d.ts +2 -0
  3. package/cjs/commands/create-new-app/get-app-path.d.ts.map +1 -0
  4. package/cjs/commands/create-new-app/get-app-path.js +8 -0
  5. package/cjs/commands/create-new-app/get-app-path.js.map +1 -0
  6. package/cjs/commands/create-new-app/index.d.ts +2 -0
  7. package/cjs/commands/create-new-app/index.d.ts.map +1 -0
  8. package/cjs/commands/create-new-app/index.js +42 -0
  9. package/cjs/commands/create-new-app/index.js.map +1 -0
  10. package/cjs/commands/create-new-app/select-app-type.d.ts +2 -0
  11. package/cjs/commands/create-new-app/select-app-type.d.ts.map +1 -0
  12. package/cjs/commands/create-new-app/types.d.ts +8 -0
  13. package/cjs/commands/create-new-app/types.d.ts.map +1 -0
  14. package/cjs/commands/create-warlock-app/index.d.ts +3 -0
  15. package/cjs/commands/create-warlock-app/index.d.ts.map +1 -0
  16. package/cjs/commands/create-warlock-app/index.js +18 -0
  17. package/cjs/commands/create-warlock-app/index.js.map +1 -0
  18. package/cjs/commands/vite-react/headless-ui/index.d.ts +3 -0
  19. package/cjs/commands/vite-react/headless-ui/index.d.ts.map +1 -0
  20. package/cjs/commands/vite-react/headless-ui/types.d.ts +4 -0
  21. package/cjs/commands/vite-react/headless-ui/types.d.ts.map +1 -0
  22. package/cjs/commands/vite-react/index.d.ts +3 -0
  23. package/cjs/commands/vite-react/index.d.ts.map +1 -0
  24. package/cjs/commands/vite-react/mantine/index.d.ts +3 -0
  25. package/cjs/commands/vite-react/mantine/index.d.ts.map +1 -0
  26. package/cjs/commands/vite-react/mantine/types.d.ts +4 -0
  27. package/cjs/commands/vite-react/mantine/types.d.ts.map +1 -0
  28. package/cjs/commands/vite-react/select-react-app.d.ts +4 -0
  29. package/cjs/commands/vite-react/select-react-app.d.ts.map +1 -0
  30. package/cjs/commands/vite-react/selectAppConfigurations.d.ts +3 -0
  31. package/cjs/commands/vite-react/selectAppConfigurations.d.ts.map +1 -0
  32. package/cjs/commands/vite-react/tailwind-css/index.d.ts +3 -0
  33. package/cjs/commands/vite-react/tailwind-css/index.d.ts.map +1 -0
  34. package/cjs/commands/vite-react/tailwind-css/types.d.ts +4 -0
  35. package/cjs/commands/vite-react/tailwind-css/types.d.ts.map +1 -0
  36. package/cjs/commands/vite-react/types.d.ts +4 -0
  37. package/cjs/commands/vite-react/types.d.ts.map +1 -0
  38. package/cjs/helpers/app.d.ts +51 -0
  39. package/cjs/helpers/app.d.ts.map +1 -0
  40. package/cjs/helpers/app.js +127 -0
  41. package/cjs/helpers/app.js.map +1 -0
  42. package/cjs/helpers/exec.d.ts +10 -0
  43. package/cjs/helpers/exec.d.ts.map +1 -0
  44. package/cjs/helpers/exec.js +69 -0
  45. package/cjs/helpers/exec.js.map +1 -0
  46. package/cjs/helpers/package-manager.d.ts +5 -0
  47. package/cjs/helpers/package-manager.d.ts.map +1 -0
  48. package/cjs/helpers/package-manager.js +16 -0
  49. package/cjs/helpers/package-manager.js.map +1 -0
  50. package/cjs/helpers/paths.d.ts +4 -0
  51. package/cjs/helpers/paths.d.ts.map +1 -0
  52. package/cjs/helpers/paths.js +5 -0
  53. package/cjs/helpers/paths.js.map +1 -0
  54. package/cjs/helpers/project-builder-helpers.d.ts +7 -0
  55. package/cjs/helpers/project-builder-helpers.d.ts.map +1 -0
  56. package/cjs/helpers/project-builder-helpers.js +44 -0
  57. package/cjs/helpers/project-builder-helpers.js.map +1 -0
  58. package/cjs/index.d.ts +2 -0
  59. package/cjs/index.d.ts.map +1 -0
  60. package/cjs/index.js +7 -0
  61. package/cjs/index.js.map +1 -0
  62. package/create-app.js +5 -0
  63. package/esm/commands/create-new-app/get-app-path.d.ts +2 -0
  64. package/esm/commands/create-new-app/get-app-path.d.ts.map +1 -0
  65. package/esm/commands/create-new-app/get-app-path.js +8 -0
  66. package/esm/commands/create-new-app/get-app-path.js.map +1 -0
  67. package/esm/commands/create-new-app/index.d.ts +2 -0
  68. package/esm/commands/create-new-app/index.d.ts.map +1 -0
  69. package/esm/commands/create-new-app/index.js +42 -0
  70. package/esm/commands/create-new-app/index.js.map +1 -0
  71. package/esm/commands/create-new-app/select-app-type.d.ts +2 -0
  72. package/esm/commands/create-new-app/select-app-type.d.ts.map +1 -0
  73. package/esm/commands/create-new-app/types.d.ts +8 -0
  74. package/esm/commands/create-new-app/types.d.ts.map +1 -0
  75. package/esm/commands/create-warlock-app/index.d.ts +3 -0
  76. package/esm/commands/create-warlock-app/index.d.ts.map +1 -0
  77. package/esm/commands/create-warlock-app/index.js +18 -0
  78. package/esm/commands/create-warlock-app/index.js.map +1 -0
  79. package/esm/commands/vite-react/headless-ui/index.d.ts +3 -0
  80. package/esm/commands/vite-react/headless-ui/index.d.ts.map +1 -0
  81. package/esm/commands/vite-react/headless-ui/types.d.ts +4 -0
  82. package/esm/commands/vite-react/headless-ui/types.d.ts.map +1 -0
  83. package/esm/commands/vite-react/index.d.ts +3 -0
  84. package/esm/commands/vite-react/index.d.ts.map +1 -0
  85. package/esm/commands/vite-react/mantine/index.d.ts +3 -0
  86. package/esm/commands/vite-react/mantine/index.d.ts.map +1 -0
  87. package/esm/commands/vite-react/mantine/types.d.ts +4 -0
  88. package/esm/commands/vite-react/mantine/types.d.ts.map +1 -0
  89. package/esm/commands/vite-react/select-react-app.d.ts +4 -0
  90. package/esm/commands/vite-react/select-react-app.d.ts.map +1 -0
  91. package/esm/commands/vite-react/selectAppConfigurations.d.ts +3 -0
  92. package/esm/commands/vite-react/selectAppConfigurations.d.ts.map +1 -0
  93. package/esm/commands/vite-react/tailwind-css/index.d.ts +3 -0
  94. package/esm/commands/vite-react/tailwind-css/index.d.ts.map +1 -0
  95. package/esm/commands/vite-react/tailwind-css/types.d.ts +4 -0
  96. package/esm/commands/vite-react/tailwind-css/types.d.ts.map +1 -0
  97. package/esm/commands/vite-react/types.d.ts +4 -0
  98. package/esm/commands/vite-react/types.d.ts.map +1 -0
  99. package/esm/helpers/app.d.ts +51 -0
  100. package/esm/helpers/app.d.ts.map +1 -0
  101. package/esm/helpers/app.js +127 -0
  102. package/esm/helpers/app.js.map +1 -0
  103. package/esm/helpers/exec.d.ts +10 -0
  104. package/esm/helpers/exec.d.ts.map +1 -0
  105. package/esm/helpers/exec.js +69 -0
  106. package/esm/helpers/exec.js.map +1 -0
  107. package/esm/helpers/package-manager.d.ts +5 -0
  108. package/esm/helpers/package-manager.d.ts.map +1 -0
  109. package/esm/helpers/package-manager.js +16 -0
  110. package/esm/helpers/package-manager.js.map +1 -0
  111. package/esm/helpers/paths.d.ts +4 -0
  112. package/esm/helpers/paths.d.ts.map +1 -0
  113. package/esm/helpers/paths.js +5 -0
  114. package/esm/helpers/paths.js.map +1 -0
  115. package/esm/helpers/project-builder-helpers.d.ts +7 -0
  116. package/esm/helpers/project-builder-helpers.d.ts.map +1 -0
  117. package/esm/helpers/project-builder-helpers.js +44 -0
  118. package/esm/helpers/project-builder-helpers.js.map +1 -0
  119. package/esm/index.d.ts +2 -0
  120. package/esm/index.d.ts.map +1 -0
  121. package/esm/index.js +7 -0
  122. package/esm/index.js.map +1 -0
  123. package/package.json +44 -0
  124. package/templates/warlock/.env.example +35 -0
  125. package/templates/warlock/.eslintrc.json +44 -0
  126. package/templates/warlock/.gitattributes +1 -0
  127. package/templates/warlock/.prettierrc.json +11 -0
  128. package/templates/warlock/README.md +57 -0
  129. package/templates/warlock/_.gitignore +7 -0
  130. package/templates/warlock/package.json +60 -0
  131. package/templates/warlock/src/app/main.ts +12 -0
  132. package/templates/warlock/src/app/uploads/routes.ts +27 -0
  133. package/templates/warlock/src/app/users/controllers/auth/activate-account.ts +48 -0
  134. package/templates/warlock/src/app/users/controllers/auth/admin-login.ts +40 -0
  135. package/templates/warlock/src/app/users/controllers/auth/create-account.ts +23 -0
  136. package/templates/warlock/src/app/users/controllers/auth/forget-password.ts +39 -0
  137. package/templates/warlock/src/app/users/controllers/auth/login.ts +49 -0
  138. package/templates/warlock/src/app/users/controllers/auth/logout.ts +10 -0
  139. package/templates/warlock/src/app/users/controllers/auth/resend-activation-code.ts +45 -0
  140. package/templates/warlock/src/app/users/controllers/auth/reset-password.ts +43 -0
  141. package/templates/warlock/src/app/users/controllers/auth/verify-forget-password-code.ts +18 -0
  142. package/templates/warlock/src/app/users/controllers/profile/change-password.ts +31 -0
  143. package/templates/warlock/src/app/users/controllers/profile/my-profile.ts +10 -0
  144. package/templates/warlock/src/app/users/controllers/profile/update-profile.ts +25 -0
  145. package/templates/warlock/src/app/users/controllers/restful-users.ts +27 -0
  146. package/templates/warlock/src/app/users/events/attach-user-to-response.ts +18 -0
  147. package/templates/warlock/src/app/users/events/register-current-user-to-model-authors.ts +28 -0
  148. package/templates/warlock/src/app/users/events/update-authors.ts +19 -0
  149. package/templates/warlock/src/app/users/mail/send-forget-password-email.ts +20 -0
  150. package/templates/warlock/src/app/users/models/user/index.ts +1 -0
  151. package/templates/warlock/src/app/users/models/user/migration.ts +15 -0
  152. package/templates/warlock/src/app/users/models/user/user.ts +54 -0
  153. package/templates/warlock/src/app/users/output/user-output.ts +12 -0
  154. package/templates/warlock/src/app/users/repositories/users-repository.ts +28 -0
  155. package/templates/warlock/src/app/users/routes.ts +58 -0
  156. package/templates/warlock/src/app/users/utils/locales.ts +16 -0
  157. package/templates/warlock/src/app/utils/output.ts +18 -0
  158. package/templates/warlock/src/app/utils/router.ts +104 -0
  159. package/templates/warlock/src/config/app.ts +12 -0
  160. package/templates/warlock/src/config/auth.ts +16 -0
  161. package/templates/warlock/src/config/cache.ts +33 -0
  162. package/templates/warlock/src/config/database.ts +14 -0
  163. package/templates/warlock/src/config/http.ts +22 -0
  164. package/templates/warlock/src/config/log.ts +19 -0
  165. package/templates/warlock/src/config/mail.ts +16 -0
  166. package/templates/warlock/src/config/uploads.ts +12 -0
  167. package/templates/warlock/src/config/validation.ts +76 -0
  168. package/templates/warlock/tsconfig.json +30 -0
  169. package/templates/warlock/warlock.config.ts +9 -0
@@ -0,0 +1,45 @@
1
+ import { Random } from "@mongez/reinforcements";
2
+ import type { Request, Response } from "@warlock.js/core";
3
+ import { ExistsRule } from "@warlock.js/core";
4
+ import { User } from "app/users/models/user";
5
+
6
+ export default async function resendActivationCode(
7
+ request: Request,
8
+ response: Response,
9
+ ) {
10
+ //
11
+ const user = await User.first({
12
+ email: request.input("email"),
13
+ });
14
+
15
+ if (!user) {
16
+ return response.badRequest({
17
+ error: "User not found",
18
+ });
19
+ }
20
+
21
+ if (user.get("isActive")) {
22
+ return response.badRequest({
23
+ error: "User already activated",
24
+ });
25
+ }
26
+
27
+ user
28
+ .save({
29
+ activationCode: Random.int(100000, 999999),
30
+ codeExpiresAt: true,
31
+ })
32
+ .then(() => {
33
+ // send mail
34
+ });
35
+
36
+ return response.success({
37
+ message: "Activation code sent",
38
+ });
39
+ }
40
+
41
+ resendActivationCode.validation = {
42
+ rules: {
43
+ email: ["required", "email", new ExistsRule(User, "email").insensitive()],
44
+ },
45
+ };
@@ -0,0 +1,43 @@
1
+ import { ExistsRule, type Request, type Response } from "@warlock.js/core";
2
+ import { User } from "app/users/models/user";
3
+
4
+ export default async function resetPassword(
5
+ request: Request<User>,
6
+ response: Response,
7
+ ) {
8
+ const currentUser = request.user;
9
+
10
+ currentUser.unset("activationCode", "codeExpiresAt");
11
+
12
+ currentUser.save({
13
+ password: request.input("password"),
14
+ });
15
+
16
+ request.clearCurrentUser();
17
+
18
+ return response.success();
19
+ }
20
+
21
+ resetPassword.validation = {
22
+ rules: {
23
+ email: ["required", "email", new ExistsRule(User, "email").insensitive()],
24
+ password: ["required", "confirmed", "minLength:8"],
25
+ code: ["required", "int", "length:6"],
26
+ },
27
+ validate: async (request: Request, response: Response) => {
28
+ try {
29
+ const user = await User.first({
30
+ email: request.input("email"),
31
+ activationCode: request.int("code"),
32
+ });
33
+
34
+ if (!user) {
35
+ return response.notFound();
36
+ }
37
+
38
+ request.user = user;
39
+ } catch (error: any) {
40
+ return response.badRequest(error.message);
41
+ }
42
+ },
43
+ };
@@ -0,0 +1,18 @@
1
+ import { UniqueRule, type Request, type Response } from "@warlock.js/core";
2
+ import { User } from "app/users/models/user";
3
+
4
+ export default async function verifyForgetPasswordCode(
5
+ request: Request,
6
+ response: Response,
7
+ ) {
8
+ // your code here
9
+
10
+ return response.success({});
11
+ }
12
+
13
+ verifyForgetPasswordCode.validation = {
14
+ rules: {
15
+ email: ["required", "email", new UniqueRule(User)],
16
+ code: ["required", "int", "length:6"],
17
+ },
18
+ };
@@ -0,0 +1,31 @@
1
+ import type { Request, Response } from "@warlock.js/core";
2
+ import type { User } from "app/users/models/user";
3
+
4
+ export default async function changePassword(
5
+ request: Request,
6
+ response: Response,
7
+ ) {
8
+ const user = request.user;
9
+
10
+ await user.save({
11
+ password: request.input("password"),
12
+ });
13
+
14
+ return response.success();
15
+ }
16
+
17
+ changePassword.validation = {
18
+ rules: {
19
+ currentPassword: ["required"],
20
+ password: ["required", "minLength:8", "confirmed"],
21
+ },
22
+ validate: (request: Request<User>, response: Response) => {
23
+ const user = request.user;
24
+
25
+ if (!user.confirmPassword(request.input("currentPassword"))) {
26
+ return response.badRequest({
27
+ error: "Invalid current password",
28
+ });
29
+ }
30
+ },
31
+ };
@@ -0,0 +1,10 @@
1
+ import type { Request, Response } from "@warlock.js/core";
2
+ import type { User } from "app/users/models/user";
3
+
4
+ export default function myProfile(request: Request<User>, response: Response) {
5
+ const currentUser = request.user;
6
+
7
+ return response.success({
8
+ user: currentUser,
9
+ });
10
+ }
@@ -0,0 +1,25 @@
1
+ import type { Request, Response } from "@warlock.js/core";
2
+ import { UniqueRule } from "@warlock.js/core";
3
+ import { User } from "app/users/models/user";
4
+
5
+ export default async function updateProfile(
6
+ request: Request<User>,
7
+ response: Response,
8
+ ) {
9
+ await request.user.save(request.validated());
10
+
11
+ return response.success();
12
+ }
13
+
14
+ updateProfile.validation = {
15
+ rules: {
16
+ name: ["required", "minLength:2"],
17
+ gender: ["in:male,female"],
18
+ phoneNumber: ["required", new UniqueRule(User).exceptCurrentUser()],
19
+ email: [
20
+ "required",
21
+ "email",
22
+ new UniqueRule(User).insensitive().exceptCurrentUser(),
23
+ ],
24
+ },
25
+ };
@@ -0,0 +1,27 @@
1
+ import type { RouteResource } from "@warlock.js/core";
2
+ import { Restful, UniqueRule } from "@warlock.js/core";
3
+ import { User } from "../models/user";
4
+ import usersRepository from "../repositories/users-repository";
5
+
6
+ class RestfulUsers extends Restful<User> implements RouteResource {
7
+ /**
8
+ * {@inheritDoc}
9
+ */
10
+ protected repository = usersRepository;
11
+
12
+ /**
13
+ * {@inheritDoc}
14
+ */
15
+ public validation: RouteResource["validation"] = {
16
+ create: {
17
+ rules: {
18
+ name: ["required", "min:2"],
19
+ // If the request is a create request, except current id will be ignored
20
+ // otherwise, the id in the update request will be used as a filter to ignore the current id
21
+ email: ["required", "email", new UniqueRule(User).exceptCurrentId()],
22
+ },
23
+ },
24
+ };
25
+ }
26
+
27
+ export const restfulUsers = new RestfulUsers();
@@ -0,0 +1,18 @@
1
+ import { Response } from "@warlock.js/core";
2
+
3
+ export function attachCurrentUserToResponse(response: Response) {
4
+ if (!response.isJson) return;
5
+
6
+ const responseData = response.body;
7
+
8
+ if (!responseData || responseData.user) return;
9
+
10
+ const currentUser = response.request.user;
11
+
12
+ if (!currentUser) return;
13
+
14
+ responseData.user = currentUser;
15
+ }
16
+
17
+ // add current user to response
18
+ Response.on("sending", attachCurrentUserToResponse);
@@ -0,0 +1,28 @@
1
+ /**
2
+ * This event is responsible for adding the current user to any model that is being saved
3
+ * Such as createdBy and updatedBy so you don't need to add it manually.
4
+ */
5
+ import { isEmpty } from "@mongez/supportive-is";
6
+ import { Model } from "@warlock.js/cascade";
7
+ import { useRequestStore } from "@warlock.js/core";
8
+ import type { User } from "../models/user";
9
+
10
+ Model.events()
11
+ .onSaving((model: Model, oldModel?: Model) => {
12
+ const { user } = useRequestStore<User>();
13
+
14
+ if (!user) return;
15
+
16
+ if (!oldModel && isEmpty(model.get("createdBy"))) {
17
+ model.set("createdBy", user.embeddedData);
18
+ }
19
+
20
+ model.set("updatedBy", user.embeddedData);
21
+ })
22
+ .onDeleting((model: Model) => {
23
+ const { user } = useRequestStore<User>();
24
+
25
+ if (!user || user.userType === "guest") return;
26
+
27
+ model.set("deletedBy", user.embeddedData);
28
+ });
@@ -0,0 +1,19 @@
1
+ import { Aggregate, database } from "@warlock.js/cascade";
2
+ import { User } from "../models/user";
3
+
4
+ User.events().onSaved(async (user: User) => {
5
+ // list all collections in the database
6
+ const collections = await database.listCollectionNames();
7
+
8
+ // this will update the createdBy and updatedBy fields in all collections
9
+ // it may take some time if you have a lot of collections or documents but it's the best way to do it
10
+ for (const collection of collections) {
11
+ new Aggregate(collection).where("createdBy.id", user.id).update({
12
+ createdBy: user.embeddedData,
13
+ });
14
+
15
+ new Aggregate(collection).where("updatedBy.id", user.id).update({
16
+ updatedBy: user.embeddedData,
17
+ });
18
+ }
19
+ });
@@ -0,0 +1,20 @@
1
+ import { sendMail } from "@warlock.js/core";
2
+ import type { User } from "../models/user";
3
+
4
+ export default async function sendForgetPasswordEmail(user: User) {
5
+ await sendMail({
6
+ to: user.get("email"),
7
+ subject: "Reset Password",
8
+ html: `
9
+ <h3>Hello, ${user.get("name")}</h3>
10
+
11
+ <p>Use the following code to reset your password:</p>
12
+
13
+ <p>Please note that this code will expire in 10 minutes.</p>
14
+
15
+ <p>Your reset password code is: <strong>${user.get(
16
+ "activationCode",
17
+ )}</strong></p>
18
+ `,
19
+ });
20
+ }
@@ -0,0 +1 @@
1
+ export * from "./user";
@@ -0,0 +1,15 @@
1
+ import { migrationOffice } from "@warlock.js/cascade";
2
+ import { User } from "./user";
3
+
4
+ export default migrationOffice.register({
5
+ name: "users",
6
+ blueprint: User.blueprint(),
7
+ up: blueprint => {
8
+ blueprint.unique("id");
9
+ blueprint.unique("email");
10
+ },
11
+ down(blueprint) {
12
+ blueprint.dropUniqueIndex("id");
13
+ blueprint.dropUniqueIndex("email");
14
+ },
15
+ });
@@ -0,0 +1,54 @@
1
+ import { Auth, castPassword } from "@warlock.js/auth";
2
+ import type { Casts, Document } from "@warlock.js/cascade";
3
+ import { castEmail, expiresAfter } from "@warlock.js/cascade";
4
+ import { uploadable } from "@warlock.js/core";
5
+ import UserOutput from "../../output/user-output";
6
+
7
+ export class User extends Auth {
8
+ /**
9
+ * Collection name
10
+ */
11
+ public static collection = "users";
12
+
13
+ /**
14
+ * Output
15
+ */
16
+ public static output = UserOutput;
17
+
18
+ /**
19
+ * {@inheritdoc}
20
+ */
21
+ public syncWith = [];
22
+
23
+ /**
24
+ * Get user type
25
+ */
26
+ public get userType(): string {
27
+ return "user";
28
+ }
29
+
30
+ /**
31
+ * {@inheritDoc}
32
+ */
33
+ public defaultValue: Document = {
34
+ isActive: false,
35
+ };
36
+
37
+ /**
38
+ * {@inheritDoc}
39
+ */
40
+ protected casts: Casts = {
41
+ name: "string",
42
+ isActive: "boolean",
43
+ image: uploadable,
44
+ email: castEmail,
45
+ password: castPassword,
46
+ activationCode: "int",
47
+ codeExpiresAt: expiresAfter(30, "minutes"),
48
+ };
49
+
50
+ /**
51
+ * {@inheritdoc}
52
+ */
53
+ public embedded = ["id", "name", "email"];
54
+ }
@@ -0,0 +1,12 @@
1
+ import { Output, type FinalOutput } from "@warlock.js/core";
2
+ import { withBaseOutputDetails } from "app/utils/output";
3
+
4
+ export default class UserOutput extends Output {
5
+ /**
6
+ * Output data
7
+ */
8
+ protected output: FinalOutput = withBaseOutputDetails({
9
+ name: "string",
10
+ email: "string",
11
+ });
12
+ }
@@ -0,0 +1,28 @@
1
+ import type { FilterByOptions, RepositoryOptions } from "@warlock.js/core";
2
+ import { RepositoryManager } from "@warlock.js/core";
3
+
4
+ import { User } from "../models/user";
5
+
6
+ export class UsersRepository extends RepositoryManager<User> {
7
+ /**
8
+ * {@inheritDoc}
9
+ */
10
+ public model = User;
11
+
12
+ /**
13
+ * List default options
14
+ */
15
+ protected defaultOptions: RepositoryOptions = this.withDefaultOptions({});
16
+
17
+ /**
18
+ * Filter By options
19
+ */
20
+ protected filterBy: FilterByOptions = this.withDefaultFilters({
21
+ name: "like",
22
+ isActive: "bool",
23
+ });
24
+ }
25
+
26
+ const usersRepository = new UsersRepository();
27
+
28
+ export default usersRepository;
@@ -0,0 +1,58 @@
1
+ import { guestLogin } from "@warlock.js/auth";
2
+ import { router } from "@warlock.js/core";
3
+ import {
4
+ adminPath,
5
+ guarded,
6
+ guardedAdmin,
7
+ guardedGuest,
8
+ guardedGuestAdmin,
9
+ } from "app/utils/router";
10
+ import activateAccount from "./controllers/auth/activate-account";
11
+ import adminLogin from "./controllers/auth/admin-login";
12
+ import createAccount from "./controllers/auth/create-account";
13
+ import forgetPassword from "./controllers/auth/forget-password";
14
+ import login from "./controllers/auth/login";
15
+ import logout from "./controllers/auth/logout";
16
+ import resendActivationCode from "./controllers/auth/resend-activation-code";
17
+ import resetPassword from "./controllers/auth/reset-password";
18
+ import verifyForgetPasswordCode from "./controllers/auth/verify-forget-password-code";
19
+ import changePassword from "./controllers/profile/change-password";
20
+ import myProfile from "./controllers/profile/my-profile";
21
+ import updateProfile from "./controllers/profile/update-profile";
22
+ import { restfulUsers } from "./controllers/restful-users";
23
+
24
+ // guest login
25
+ // If you are going to use guest as a user type, you can use this route
26
+ // otherwise, you can remove this route, also you may remove the guest model from the src/config/auth.ts config file
27
+ router.post([adminPath("/login/guests"), "/login/guests"], guestLogin);
28
+
29
+ // admin auth
30
+ guardedGuestAdmin(() => {
31
+ router.post("/login", adminLogin);
32
+ router.post("/forget-password", forgetPassword);
33
+ router.post("/reset-password", resetPassword);
34
+ });
35
+
36
+ guardedAdmin(() => {
37
+ // REST API for users
38
+ router.restfulResource("/users", restfulUsers);
39
+ });
40
+
41
+ // user auth
42
+ guardedGuest(() => {
43
+ router.post("/login", login);
44
+ router.post("/register", createAccount);
45
+ router.post("/register/verify", activateAccount);
46
+ router.post("/resend-activation-code", resendActivationCode);
47
+ router.post("/forget-password", forgetPassword);
48
+ router.post("/forget-password/verify-code", verifyForgetPasswordCode);
49
+ router.post("/reset-password", resetPassword);
50
+ });
51
+
52
+ // profile routes
53
+ guarded(() => {
54
+ router.get("/me", myProfile);
55
+ router.post("/me", updateProfile);
56
+ router.post("/logout", logout);
57
+ router.post("/change-password", changePassword);
58
+ });
@@ -0,0 +1,16 @@
1
+ import { groupedTranslations } from "@mongez/localization";
2
+
3
+ groupedTranslations("auth", {
4
+ confirmRegistrationSubject: {
5
+ en: "Activate your account",
6
+ ar: "تفعيل حسابك",
7
+ },
8
+ invalidCredentials: {
9
+ en: "Invalid credentials",
10
+ ar: "بيانات الدخول غير صحيحة",
11
+ },
12
+ accountNotActivated: {
13
+ en: "Your account is not activated",
14
+ ar: "حسابك غير مفعل",
15
+ },
16
+ });
@@ -0,0 +1,18 @@
1
+ import type { FinalOutput } from "@warlock.js/core";
2
+ import UserOutput from "app/users/output/user-output";
3
+
4
+ /**
5
+ * Merge the output with this function will return the base output details
6
+ * Only and only if any of these keys are present
7
+ */
8
+ export function withBaseOutputDetails(moreOptions: FinalOutput): FinalOutput {
9
+ return {
10
+ id: "integer",
11
+ isActive: "boolean",
12
+ createdAt: "date",
13
+ updatedAt: "date",
14
+ createdBy: UserOutput,
15
+ updatedBy: UserOutput,
16
+ ...moreOptions,
17
+ };
18
+ }
@@ -0,0 +1,104 @@
1
+ import { authMiddleware } from "@warlock.js/auth";
2
+ import {
3
+ router,
4
+ useRequestStore,
5
+ type Middleware,
6
+ type RouterGroupCallback,
7
+ } from "@warlock.js/core";
8
+
9
+ export const adminPath = (path: string) => `/admin${path}`;
10
+
11
+ /**
12
+ * Check if the current request is for admin
13
+ */
14
+ export const isAdminRequest = () => {
15
+ const { request } = useRequestStore();
16
+
17
+ return request.path.includes("/admin");
18
+ };
19
+
20
+ /**
21
+ * Add routes Group
22
+ */
23
+ const adminRoutes = (callback: RouterGroupCallback) => {
24
+ return router.group(
25
+ {
26
+ prefix: "/admin",
27
+ name: "admin",
28
+ },
29
+ callback,
30
+ );
31
+ };
32
+
33
+ /**
34
+ * Register guarded routes that requires user to be logged in to access them.
35
+ */
36
+ export const guarded = (
37
+ callback: RouterGroupCallback,
38
+ moreMiddlewares: Middleware[] = [],
39
+ ) => {
40
+ return router.group(
41
+ {
42
+ name: "guarded.user",
43
+ middleware: [authMiddleware("user"), ...moreMiddlewares],
44
+ },
45
+ callback,
46
+ );
47
+ };
48
+
49
+ /**
50
+ * Only guests can access these routes.
51
+ */
52
+ export const guardedGuest = (callback: RouterGroupCallback) => {
53
+ return router.group(
54
+ {
55
+ name: "guarded.guest",
56
+ middleware: [authMiddleware("guest")],
57
+ },
58
+ callback,
59
+ );
60
+ };
61
+
62
+ /**
63
+ * Guarded guest routes for admin
64
+ */
65
+ export const guardedGuestAdmin = (callback: RouterGroupCallback) => {
66
+ return adminRoutes(() => {
67
+ router.group(
68
+ {
69
+ name: "guarded.guest",
70
+ middleware: [authMiddleware("guest")],
71
+ },
72
+ callback,
73
+ );
74
+ });
75
+ };
76
+
77
+ /**
78
+ * Only admin can access these routes.
79
+ */
80
+ export const guardedAdmin = (callback: RouterGroupCallback) => {
81
+ return adminRoutes(() => {
82
+ router.group(
83
+ {
84
+ name: "guarded.user",
85
+ middleware: [authMiddleware("user")],
86
+ },
87
+ callback,
88
+ );
89
+ });
90
+ };
91
+
92
+ /**
93
+ * Public routes that doesn't require user to be logged in to access them.
94
+ * Just requires an access token.
95
+ */
96
+ export const publicRoutes = (callback: RouterGroupCallback) => {
97
+ return router.group(
98
+ {
99
+ name: "public",
100
+ middleware: [authMiddleware()],
101
+ },
102
+ callback,
103
+ );
104
+ };
@@ -0,0 +1,12 @@
1
+ import { env } from "@mongez/dotenv";
2
+ import type { AppConfigurations } from "@warlock.js/core";
3
+
4
+ const appConfigurations: AppConfigurations = {
5
+ appName: env("APP_NAME", "Warlock"),
6
+ timezone: env("TIMEZONE", "UTC"),
7
+ baseUrl: env("BASE_URL", "http://localhost:3000"),
8
+ localeCode: env("LOCALE_CODE", "en"),
9
+ localeCodes: ["en", "ar"],
10
+ };
11
+
12
+ export default appConfigurations;
@@ -0,0 +1,16 @@
1
+ import { env } from "@mongez/dotenv";
2
+ import type { AuthConfigurations } from "@warlock.js/auth";
3
+ import { Guest } from "@warlock.js/auth";
4
+ import { User } from "app/users/models/user";
5
+
6
+ const authConfigurations: AuthConfigurations = {
7
+ userType: {
8
+ guest: Guest,
9
+ user: User,
10
+ },
11
+ jwt: {
12
+ secret: env("JWT_SECRET"),
13
+ },
14
+ };
15
+
16
+ export default authConfigurations;
@@ -0,0 +1,33 @@
1
+ import { env } from "@mongez/dotenv";
2
+ import type { CacheConfigurations } from "@warlock.js/cache";
3
+ import {
4
+ FileCacheDriver,
5
+ MemoryCacheDriver,
6
+ RedisCacheDriver,
7
+ } from "@warlock.js/cache";
8
+
9
+ const globalPrefix = () => {
10
+ return env("CACHE_PREFIX", env("APP_NAME", "warlock"));
11
+ };
12
+
13
+ const cacheConfigurations: CacheConfigurations = {
14
+ drivers: {
15
+ file: FileCacheDriver,
16
+ memory: MemoryCacheDriver,
17
+ redis: RedisCacheDriver,
18
+ },
19
+ default: env("CACHE_DRIVER", "memory"),
20
+ options: {
21
+ memory: {
22
+ globalPrefix,
23
+ },
24
+ redis: {
25
+ host: env("REDIS_HOST"),
26
+ port: env("REDIS_PORT"),
27
+ url: env("REDIS_URL"),
28
+ globalPrefix,
29
+ },
30
+ },
31
+ };
32
+
33
+ export default cacheConfigurations;