Compare commits

...

5 commits

Author SHA1 Message Date
Ethan Lane c1ca37283c Add give currency timer
All checks were successful
Test / build (push) Successful in 2m29s
2024-05-06 17:09:59 +01:00
Ethan Lane a4e9242020 Merge branch 'develop' into feature/204-coins-cron 2024-05-06 16:48:39 +01:00
RenovateBot f07058d369 Update dependency jest-mock-extended to v3.0.7 (#218)
All checks were successful
Deploy To Stage / build (push) Successful in 11s
Deploy To Stage / deploy (push) Successful in 17s
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [jest-mock-extended](https://github.com/marchaos/jest-mock-extended) | dependencies | patch | [`3.0.6` -> `3.0.7`](https://renovatebot.com/diffs/npm/jest-mock-extended/3.0.6/3.0.7) |

---

### Release Notes

<details>
<summary>marchaos/jest-mock-extended (jest-mock-extended)</summary>

### [`v3.0.7`](https://github.com/marchaos/jest-mock-extended/releases/tag/3.0.7)

[Compare Source](77a64ae832...3.0.7)

Bumped ts-essentials

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4wLjAiLCJ1cGRhdGVkSW5WZXIiOiIzNy4wLjAiLCJ0YXJnZXRCcmFuY2giOiJkZXZlbG9wIn0=-->

Reviewed-on: #218
Co-authored-by: Renovate Bot <renovate@vylpes.com>
Co-committed-by: Renovate Bot <renovate@vylpes.com>
2024-05-06 16:44:43 +01:00
RenovateBot f0870f0d61 Update dependency @types/node to v20.12.8 (#217)
All checks were successful
Deploy To Stage / build (push) Successful in 2m29s
Deploy To Stage / deploy (push) Successful in 15s
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node) ([source](https://github.com/DefinitelyTyped/DefinitelyTyped)) | devDependencies | patch | [`20.12.7` -> `20.12.8`](https://renovatebot.com/diffs/npm/@types%2fnode/20.12.7/20.12.8) |

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4wLjAiLCJ1cGRhdGVkSW5WZXIiOiIzNy4wLjAiLCJ0YXJnZXRCcmFuY2giOiJkZXZlbG9wIn0=-->

Reviewed-on: #217
Co-authored-by: Renovate Bot <renovate@vylpes.com>
Co-committed-by: Renovate Bot <renovate@vylpes.com>
2024-05-06 16:41:08 +01:00
Ethan Lane fca199d9bd Make claim button use currency to claim (#216)
All checks were successful
Deploy To Stage / build (push) Successful in 2m30s
Deploy To Stage / deploy (push) Successful in 14s
# Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.

#201

## Type of change

Please delete options that are not relevant.

- [x] New feature (non-breaking change which adds functionality)

# How Has This Been Tested?

Please describe the tests that you ran to verify the changes. Provide instructions so we can reproduce. Please also list any relevant details to your test configuration.

# Checklist

- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that provde my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream modules

Reviewed-on: #216
Reviewed-by: VylpesTester <tester@vylpes.com>
Co-authored-by: Ethan Lane <ethan@vylpes.com>
Co-committed-by: Ethan Lane <ethan@vylpes.com>
2024-05-03 18:37:08 +01:00
12 changed files with 93 additions and 39 deletions

View file

@ -13,23 +13,24 @@ BOT_OWNERID=147392775707426816
BOT_CLIENTID=682942374040961060 BOT_CLIENTID=682942374040961060
BOT_ENV=4 BOT_ENV=4
BOT_ADMINS=147392775707426816,887272961504071690 BOT_ADMINS=147392775707426816,887272961504071690
BOT_LOGLEVEL=info
ABOUT_FUNDING= ABOUT_FUNDING=
ABOUT_REPO= ABOUT_REPO=
DATA_DIR= DATA_DIR=./.temp
DB_HOST= DB_HOST=127.0.0.1
DB_PORT= DB_PORT=3301
DB_NAME= DB_NAME=carddrop
DB_AUTH_USER= DB_AUTH_USER=
DB_AUTH_PASS= DB_AUTH_PASS=
DB_SYNC= DB_SYNC=
DB_LOGGING= DB_LOGGING=
DB_DATA_LOCATION=~/.docker DB_DATA_LOCATION=./.temp/database
DB_CARD_FILE=:memory: DB_CARD_FILE=:memory:
EXPRESS_PORT=3303 EXPRESS_PORT=3302
GDRIVESYNC_AUTO=true GDRIVESYNC_AUTO=true

View file

@ -53,12 +53,13 @@ jobs:
DATA_DIR: ${{ secrets.PROD_DATA_DIR }} DATA_DIR: ${{ secrets.PROD_DATA_DIR }}
GDRIVESYNC_AUTO: ${{ vars.PROD_GDRIVESYNC_AUTO }} GDRIVESYNC_AUTO: ${{ vars.PROD_GDRIVESYNC_AUTO }}
EXPRESS_PORT: ${{ secrets.PROD_EXPRESS_PORT }} EXPRESS_PORT: ${{ secrets.PROD_EXPRESS_PORT }}
BOT_LOGLEVEL: ${{ vars.PROD_BOT_LOGLEVEL }}
with: with:
host: ${{ secrets.PROD_SSH_HOST }} host: ${{ secrets.PROD_SSH_HOST }}
username: ${{ secrets.PROD_SSH_USER }} username: ${{ secrets.PROD_SSH_USER }}
key: ${{ secrets.PROD_SSH_KEY }} key: ${{ secrets.PROD_SSH_KEY }}
port: ${{ secrets.PROD_SSH_PORT }} port: ${{ secrets.PROD_SSH_PORT }}
envs: DB_NAME,DB_AUTH_USER,DB_AUTH_PASS,DB_HOST,DB_PORT,DB_ROOT_HOST,DB_SYNC,DB_LOGGING,DB_DATA_LOCATION,BOT_TOKEN,BOT_VER,BOT_AUTHOR,BOT_OWNERID,BOT_CLIENTID,ABOUT_FUNDING,ABOUT_REPO,BOT_ENV,BOT_ADMINS,DATA_DIR,GDRIVESYNC_AUTO,SERVER_PATH,EXPRESS_PORT envs: DB_NAME,DB_AUTH_USER,DB_AUTH_PASS,DB_HOST,DB_PORT,DB_ROOT_HOST,DB_SYNC,DB_LOGGING,DB_DATA_LOCATION,BOT_TOKEN,BOT_VER,BOT_AUTHOR,BOT_OWNERID,BOT_CLIENTID,ABOUT_FUNDING,ABOUT_REPO,BOT_ENV,BOT_ADMINS,DATA_DIR,GDRIVESYNC_AUTO,SERVER_PATH,EXPRESS_PORT,BOT_LOGLEVEL
script: | script: |
source .sshrc \ source .sshrc \
&& cd /home/vylpes/apps/card-drop/card-drop_prod \ && cd /home/vylpes/apps/card-drop/card-drop_prod \

View file

@ -53,12 +53,13 @@ jobs:
DATA_DIR: ${{ secrets.STAGE_DATA_DIR }} DATA_DIR: ${{ secrets.STAGE_DATA_DIR }}
GDRIVESYNC_AUTO: ${{ vars.STAGE_GDRIVESYNC_AUTO }} GDRIVESYNC_AUTO: ${{ vars.STAGE_GDRIVESYNC_AUTO }}
EXPRESS_PORT: ${{ secrets.STAGE_EXPRESS_PORT }} EXPRESS_PORT: ${{ secrets.STAGE_EXPRESS_PORT }}
BOT_LOGLEVEL: ${{ vars.STAGE_BOT_LOGLEVEL }}
with: with:
host: ${{ secrets.STAGE_SSH_HOST }} host: ${{ secrets.STAGE_SSH_HOST }}
username: ${{ secrets.STAGE_SSH_USER }} username: ${{ secrets.STAGE_SSH_USER }}
key: ${{ secrets.STAGE_SSH_KEY }} key: ${{ secrets.STAGE_SSH_KEY }}
port: ${{ secrets.STAGE_SSH_PORT }} port: ${{ secrets.STAGE_SSH_PORT }}
envs: DB_NAME,DB_AUTH_USER,DB_AUTH_PASS,DB_HOST,DB_PORT,DB_ROOT_HOST,DB_SYNC,DB_LOGGING,DB_DATA_LOCATION,BOT_TOKEN,BOT_VER,BOT_AUTHOR,BOT_OWNERID,BOT_CLIENTID,ABOUT_FUNDING,ABOUT_REPO,BOT_ENV,BOT_ADMINS,DATA_DIR,GDRIVESYNC_AUTO,SERVER_PATH,EXPRESS_PORT envs: DB_NAME,DB_AUTH_USER,DB_AUTH_PASS,DB_HOST,DB_PORT,DB_ROOT_HOST,DB_SYNC,DB_LOGGING,DB_DATA_LOCATION,BOT_TOKEN,BOT_VER,BOT_AUTHOR,BOT_OWNERID,BOT_CLIENTID,ABOUT_FUNDING,ABOUT_REPO,BOT_ENV,BOT_ADMINS,DATA_DIR,GDRIVESYNC_AUTO,SERVER_PATH,EXPRESS_PORT,BOT_LOGLEVEL
script: | script: |
source .sshrc \ source .sshrc \
&& cd /home/vylpes/apps/card-drop/card-drop_stage \ && cd /home/vylpes/apps/card-drop/card-drop_stage \

22
package-lock.json generated
View file

@ -1906,9 +1906,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.12.7", "version": "20.12.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.8.tgz",
"integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", "integrity": "sha512-NU0rJLJnshZWdE/097cdCBbyW1h4hEg0xpovcoAQYHl8dnEyp/NAOiE45pvc+Bd1Dt+2r94v2eGFpQJ4R7g+2w==",
"dependencies": { "dependencies": {
"undici-types": "~5.26.4" "undici-types": "~5.26.4"
} }
@ -6831,11 +6831,11 @@
} }
}, },
"node_modules/jest-mock-extended": { "node_modules/jest-mock-extended": {
"version": "3.0.6", "version": "3.0.7",
"resolved": "https://registry.npmjs.org/jest-mock-extended/-/jest-mock-extended-3.0.6.tgz", "resolved": "https://registry.npmjs.org/jest-mock-extended/-/jest-mock-extended-3.0.7.tgz",
"integrity": "sha512-DJuEoFzio0loqdX8NIwkbE9dgIXNzaj//pefOQxGkoivohpxbSQeNHCAiXkDNA/fmM4EIJDoZnSibP4w3dUJ9g==", "integrity": "sha512-7lsKdLFcW9B9l5NzZ66S/yTQ9k8rFtnwYdCNuRU/81fqDWicNDVhitTSPnrGmNeNm0xyw0JHexEOShrIKRCIRQ==",
"dependencies": { "dependencies": {
"ts-essentials": "^9.4.2" "ts-essentials": "^10.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"jest": "^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0", "jest": "^24.0.0 || ^25.0.0 || ^26.0.0 || ^27.0.0 || ^28.0.0 || ^29.0.0",
@ -10870,11 +10870,11 @@
} }
}, },
"node_modules/ts-essentials": { "node_modules/ts-essentials": {
"version": "9.4.2", "version": "10.0.0",
"resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-9.4.2.tgz", "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-10.0.0.tgz",
"integrity": "sha512-mB/cDhOvD7pg3YCLk2rOtejHjjdSi9in/IBYE13S+8WA5FBSraYf4V/ws55uvs0IvQ/l0wBOlXy5yBNZ9Bl8ZQ==", "integrity": "sha512-77FHNJEyysF9+1s4G6eejuA1lxw7uMchT3ZPy3CIbh7GIunffpshtM8pTe5G6N5dpOzNevqRHew859ceLWVBfw==",
"peerDependencies": { "peerDependencies": {
"typescript": ">=4.1.0" "typescript": ">=4.5.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"typescript": { "typescript": {

View file

@ -58,12 +58,4 @@ if (!existsSync(`${process.env.DATA_DIR}/cards`) && process.env.GDRIVESYNC_AUTO
}); });
} }
client.start(); client.start();
const timerHelper = new TimerHelper();
const id = timerHelper.AddTimer('* * * * * *', 'Europe/London', GiveCurrency);
console.log(`Timer Created: ${id}`);
timerHelper.StartAllTimers();

View file

@ -7,6 +7,7 @@ import AppLogger from "../client/appLogger";
import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata"; import CardDropHelperMetadata from "../helpers/CardDropHelperMetadata";
import { readFileSync } from "fs"; import { readFileSync } from "fs";
import path from "path"; import path from "path";
import User from "../database/entities/app/User";
export default class Claim extends ButtonEvent { export default class Claim extends ButtonEvent {
public override async execute(interaction: ButtonInteraction) { public override async execute(interaction: ButtonInteraction) {
@ -41,6 +42,17 @@ export default class Claim extends ButtonEvent {
await inventory.Save(Inventory, inventory); await inventory.Save(Inventory, inventory);
let user = await User.FetchOneById(User, userId) || new User(userId, 300);
AppLogger.LogSilly("Button/Claim", `${user.Id} has ${user.Currency} currency`);
if (!user.RemoveCurrency(10)) {
await interaction.reply(`Not enough currency! You need 10 currency, you have ${user.Currency}`);
return;
}
await user.Save(User, user);
const claim = new eClaim(claimId); const claim = new eClaim(claimId);
claim.SetInventory(inventory); claim.SetInventory(inventory);

View file

@ -14,6 +14,8 @@ import Webhooks from "../webhooks";
import CardMetadataFunction from "../Functions/CardMetadataFunction"; import CardMetadataFunction from "../Functions/CardMetadataFunction";
import { SeriesMetadata } from "../contracts/SeriesMetadata"; import { SeriesMetadata } from "../contracts/SeriesMetadata";
import AppLogger from "./appLogger"; import AppLogger from "./appLogger";
import TimerHelper from "../helpers/TimerHelper";
import GiveCurrency from "../timers/GiveCurrency";
export class CoreClient extends Client { export class CoreClient extends Client {
private static _commandItems: ICommandItem[]; private static _commandItems: ICommandItem[];
@ -23,6 +25,7 @@ export class CoreClient extends Client {
private _events: Events; private _events: Events;
private _util: Util; private _util: Util;
private _webhooks: Webhooks; private _webhooks: Webhooks;
private _timerHelper: TimerHelper;
public static ClaimId: string; public static ClaimId: string;
public static Environment: Environment; public static Environment: Environment;
@ -59,6 +62,7 @@ export class CoreClient extends Client {
this._events = new Events(); this._events = new Events();
this._util = new Util(); this._util = new Util();
this._webhooks = new Webhooks(); this._webhooks = new Webhooks();
this._timerHelper = new TimerHelper();
AppLogger.LogInfo("Client", `Environment: ${CoreClient.Environment}`); AppLogger.LogInfo("Client", `Environment: ${CoreClient.Environment}`);
@ -72,7 +76,12 @@ export class CoreClient extends Client {
} }
await AppDataSource.initialize() await AppDataSource.initialize()
.then(() => AppLogger.LogInfo("Client", "App Data Source Initialised")) .then(() => {
AppLogger.LogInfo("Client", "App Data Source Initialised");
const timerId = this._timerHelper.AddTimer("*/30 * * * * *", "Europe/London", GiveCurrency, false);
this._timerHelper.StartTimer(timerId);
})
.catch(err => { .catch(err => {
AppLogger.LogError("Client", "App Data Source Initialisation Failed"); AppLogger.LogError("Client", "App Data Source Initialisation Failed");
AppLogger.LogError("Client", err); AppLogger.LogError("Client", err);

View file

@ -27,6 +27,12 @@ export default class AppBaseEntity {
await repository.save(entity); await repository.save(entity);
} }
public static async SaveAll<T extends AppBaseEntity>(target: EntityTarget<T>, entities: DeepPartial<T>[]): Promise<void> {
const repository = AppDataSource.getRepository<T>(target);
await repository.save(entities);
}
public static async Remove<T extends AppBaseEntity>(target: EntityTarget<T>, entity: T): Promise<void> { public static async Remove<T extends AppBaseEntity>(target: EntityTarget<T>, entity: T): Promise<void> {
const repository = AppDataSource.getRepository<T>(target); const repository = AppDataSource.getRepository<T>(target);

View file

@ -13,7 +13,15 @@ export default class User extends AppBaseEntity {
@Column() @Column()
Currency: number; Currency: number;
public UpdateCurrency(currency: number) { public AddCurrency(amount: number) {
this.Currency = currency; this.Currency += amount;
}
public RemoveCurrency(amount: number): boolean {
if (this.Currency < amount) return false;
this.Currency -= amount;
return true;
} }
} }

View file

@ -5,6 +5,8 @@ interface Timer {
id: string; id: string;
job: CronJob; job: CronJob;
context: Map<string, any>; context: Map<string, any>;
onTick: ((context: Map<string, any>) => void) | ((context: Map<string, any>) => Promise<void>);
runOnStart: boolean;
} }
export default class TimerHelper { export default class TimerHelper {
@ -17,7 +19,8 @@ export default class TimerHelper {
public AddTimer( public AddTimer(
cronTime: string, cronTime: string,
timeZone: string, timeZone: string,
onTick: ((context: Map<string, any>) => void) | ((context: Map<string, any>) => Promise<void>)): string { onTick: ((context: Map<string, any>) => void) | ((context: Map<string, any>) => Promise<void>),
runOnStart: boolean = false): string {
const context = new Map<string, any>(); const context = new Map<string, any>();
const job = new CronJob( const job = new CronJob(
@ -36,13 +39,15 @@ export default class TimerHelper {
id, id,
job, job,
context, context,
onTick,
runOnStart,
}); });
return id; return id;
} }
public StartAllTimers() { public StartAllTimers() {
this._timers.forEach(timer => timer.job.start()); this._timers.forEach(timer => this.StartJob(timer));
} }
public StopAllTimers() { public StopAllTimers() {
@ -54,7 +59,7 @@ export default class TimerHelper {
if (!timer) return; if (!timer) return;
timer.job.start(); this.StartJob(timer);
} }
public StopTimer(id: string) { public StopTimer(id: string) {
@ -64,4 +69,12 @@ export default class TimerHelper {
timer.job.stop(); timer.job.stop();
} }
private StartJob(timer: Timer) {
timer.job.start();
if (timer.runOnStart) {
timer.onTick(timer.context);
}
}
} }

View file

@ -52,4 +52,8 @@ export default class Registry {
CoreClient.RegisterButtonEvent("series", new SeriesEvent()); CoreClient.RegisterButtonEvent("series", new SeriesEvent());
CoreClient.RegisterButtonEvent("trade", new TradeButtonEvent()); CoreClient.RegisterButtonEvent("trade", new TradeButtonEvent());
} }
public static RegisterTimers() {
}
} }

View file

@ -1,9 +1,16 @@
export default function GiveCurrency(context: Map<string, any>) { import AppLogger from "../client/appLogger";
let calledTimes = context.get('times') as number; import User from "../database/entities/app/User";
if (!calledTimes) calledTimes = 1; export default async function GiveCurrency(context: Map<string, any>) {
AppLogger.LogInfo("Timers/GiveCurrency", "Giving currency to every known user");
console.log(`This has been called ${calledTimes} times!`); const users = await User.FetchAll(User);
context.set('times', calledTimes + 1); for (const user of users) {
user.AddCurrency(5);
}
User.SaveAll(User, users);
AppLogger.LogInfo("Timers/GiveCurrency", `Successfully gave +5 currency to ${users.length} users`);
} }