Skip to content

Commit 37c95d9

Browse files
authored
Merge pull request #309 from Manuito83/develop
Merge for v3.7.0
2 parents 5510e1f + 25305d2 commit 37c95d9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1909
-388
lines changed

android/app/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ if (localPropertiesFile.exists()) {
1616

1717
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
1818
if (flutterVersionCode == null) {
19-
flutterVersionCode = '482'
19+
flutterVersionCode = '492'
2020
}
2121

2222
def flutterVersionName = localProperties.getProperty('flutter.versionName')
2323
if (flutterVersionName == null) {
24-
flutterVersionName = '3.6.8'
24+
flutterVersionName = '3.7.0'
2525
}
2626

2727
def keystoreProperties = new Properties()
Loading

build.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ targets:
66
- pubspec.yaml
77
- lib/models/api_v2/**
88
- lib/models/api_v2/swagger/**
9+
- lib/utils/env/**
910
builders:
11+
envied_generator|envied:
12+
options:
13+
path: .env
14+
override: true
1015
chopper_generator:
1116
options:
1217
header: "//Generated code"

cloud_functions/functions/src/foreign_stocks.ts

+147-86
Large diffs are not rendered by default.
+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import * as functions from "firebase-functions";
2+
import * as admin from "firebase-admin";
3+
import { getUsersForums } from "./torn_api";
4+
import { sendNotificationToUser } from "./notification";
5+
import { ForumsApiResponse } from "./interfaces/forums_interface";
6+
7+
const runtimeOpts = {
8+
timeoutSeconds: 120,
9+
memory: "512MB" as "512MB",
10+
};
11+
12+
export const forumsGroup = {
13+
sendForumsSubscription: functions
14+
.region("us-east4")
15+
.runWith(runtimeOpts)
16+
.pubsub.schedule("0,15,30,45 * * * *")
17+
.timeZone("Etc/UTC")
18+
.onRun(async () => {
19+
try {
20+
// Get the list of subscribers
21+
const response = await admin
22+
.firestore()
23+
.collection("players")
24+
.where("active", "==", true)
25+
.where("forumsSubscriptionsNotification", "==", true)
26+
//.where("name", "==", "Manuito")
27+
.get();
28+
29+
const subscribers = response.docs.map((d) => d.data());
30+
31+
let ipBlocks = 0;
32+
let sent = 0;
33+
34+
const promises = subscribers.map(async (thisUser) => {
35+
let errorUID = thisUser.uid;
36+
try {
37+
// Fetch user forum subscriptions
38+
const apiResponse: ForumsApiResponse = await getUsersForums(thisUser.apiKey);
39+
40+
if (apiResponse.error) {
41+
// Handle API errors
42+
if (apiResponse.error.error.includes("IP block")) {
43+
ipBlocks++;
44+
}
45+
return;
46+
}
47+
48+
// Get the user's current notified threads
49+
const previouslyNotifiedThreads: Record<string, number> = thisUser.forumsSubscriptionsNotified || {};
50+
51+
// Create a map to track updates
52+
const updatedNotifiedThreads = { ...previouslyNotifiedThreads };
53+
let hasUpdates = false;
54+
55+
// Check threads in the API response
56+
const newThreads = apiResponse.forumSubscribedThreads.filter((thread) => {
57+
const lastNotifiedCount = previouslyNotifiedThreads[thread.id] || 0;
58+
59+
if (!previouslyNotifiedThreads[thread.id]) {
60+
// If the thread is new, add it to the map
61+
updatedNotifiedThreads[thread.id] = thread.posts.total;
62+
hasUpdates = true; // Mark that we need to update Firestore
63+
return false; // Do not notify for new subscriptions
64+
}
65+
66+
// Notify if there are new posts
67+
return thread.posts.total > lastNotifiedCount;
68+
});
69+
70+
// Generate the URL for bulkDetails
71+
let bulkDetails: string;
72+
73+
if (newThreads.length === 1) {
74+
// Single thread updated
75+
const thread = newThreads[0];
76+
const totalPosts = thread.posts.total;
77+
const start = totalPosts - (totalPosts % 20); // Round down to the nearest 20
78+
bulkDetails = `https://www.torn.com/forums.php#p=threads&f=${thread.forum_id}&t=${thread.id}&start=${start}`;
79+
} else if (newThreads.length > 1) {
80+
// Multiple threads updated, we just go to the main forums page
81+
bulkDetails = `https://www.torn.com/forums.php`;
82+
}
83+
84+
// Send notifications if there are new posts
85+
if (newThreads.length > 0) {
86+
let notificationTitle = "";
87+
let notificationBody = "";
88+
89+
if (newThreads.length === 1) {
90+
// Single thread updated
91+
const thread = newThreads[0];
92+
const newPosts = thread.posts.total - (previouslyNotifiedThreads[thread.id] || 0);
93+
94+
notificationTitle = `${newPosts} new post${newPosts === 1 ? "" : "s"}`;
95+
notificationBody = `${newPosts} new post${newPosts === 1 ? "" : "s"} in ${thread.title}`;
96+
} else {
97+
// Multiple threads updated
98+
notificationTitle = `${newThreads.length} forum threads updated`;
99+
notificationBody = newThreads.map((thread) => thread.title).join(", ");
100+
}
101+
102+
// DEBUG!
103+
//functions.logger.debug(`### ${notificationTitle} \n\n ${notificationBody}`);
104+
105+
// Push notification to the user
106+
await sendNotificationToUser({
107+
token: thisUser.token,
108+
title: notificationTitle,
109+
body: notificationBody,
110+
icon: "notification_forums",
111+
color: "#00FF00", // green
112+
channelId: "Alerts forums",
113+
vibration: thisUser.vibration,
114+
bulkDetails: bulkDetails,
115+
});
116+
117+
sent++;
118+
119+
// Update the last notified counts for threads with new posts
120+
newThreads.forEach((thread) => {
121+
updatedNotifiedThreads[thread.id] = thread.posts.total;
122+
});
123+
124+
hasUpdates = true;
125+
}
126+
127+
// Remove threads that no longer exist in the API response
128+
// ONLY if there is already an update to Firestore
129+
if (hasUpdates) {
130+
Object.keys(updatedNotifiedThreads).forEach((threadId) => {
131+
if (
132+
!apiResponse.forumSubscribedThreads.some((thread) => thread.id === parseInt(threadId))
133+
) {
134+
delete updatedNotifiedThreads[threadId];
135+
}
136+
});
137+
}
138+
139+
// Update Firestore only if there are changes
140+
if (hasUpdates) {
141+
await admin.firestore().collection("players").doc(thisUser.uid).update({
142+
forumsSubscriptionsNotified: updatedNotifiedThreads,
143+
});
144+
}
145+
} catch (e) {
146+
functions.logger.warn(`ERROR FORUM SUBSCRIPTIONS for ${errorUID}\n${e}`);
147+
}
148+
});
149+
150+
// Wait for all promises to complete
151+
await Promise.all(promises);
152+
153+
// Log summary
154+
functions.logger.info(
155+
`Forums Subscription: ${subscribers.length} subscribed. ${sent} sent. ${ipBlocks} IP blocks.`
156+
);
157+
} catch (e) {
158+
functions.logger.error(`Critical error in forums subscription function: ${e}`);
159+
}
160+
}),
161+
};
162+

cloud_functions/functions/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { factionAssistGroup } from "./faction_assist";
1212
import { retalsGroup } from "./retals";
1313
import { prefsBackupGroup } from "./prefs_backup";
1414
import { troubleshootingGroup } from "./troubleshooting_notification";
15+
import { forumsGroup } from "./forums";
1516
//import { testGroup } from "./tests";
1617
//import { helperGroup } from "./helpers";
1718

@@ -35,5 +36,6 @@ export const factionAssist = factionAssistGroup;
3536
export const retals = retalsGroup;
3637
export const prefsBackup = prefsBackupGroup;
3738
export const troubleshooting = troubleshootingGroup;
39+
export const forums = forumsGroup;
3840
//export const tests = testGroup;
3941
//export const helper = helperGroup;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
export interface ForumsApiResponse {
2+
forumSubscribedThreads?: ForumThread[];
3+
error?: ApiError;
4+
}
5+
6+
export interface ApiError {
7+
code: number;
8+
error: string;
9+
}
10+
11+
export interface ForumThread {
12+
id: number;
13+
forum_id: number;
14+
title: string;
15+
posts: {
16+
new: number;
17+
total: number;
18+
};
19+
author: {
20+
id: number;
21+
username: string;
22+
karma: number;
23+
};
24+
}

cloud_functions/functions/src/players.ts

+12
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ export const playersGroup = {
101101
promises.push(manageStats("retalsNotification", -1));
102102
}
103103

104+
if (beforeStat.forumsSubscriptionsNotification) {
105+
promises.push(manageStats("forumsSubscriptionsNotification", -1));
106+
}
107+
104108
if (beforeStat.platform === "android") {
105109
promises.push(manageStats("android", -1));
106110
}
@@ -224,6 +228,12 @@ export const playersGroup = {
224228
)
225229
);
226230

231+
if (beforeStat.forumsSubscriptionsNotification !== afterStat.forumsSubscriptionsNotification)
232+
promises.push(
233+
manageStats("forumsSubscriptionsNotification", afterStat.forumsSubscriptionsNotification ? 1 : -1
234+
)
235+
);
236+
227237
if (
228238
!afterStat.energyNotification &&
229239
!afterStat.nerveNotification &&
@@ -239,6 +249,7 @@ export const playersGroup = {
239249
!afterStat.eventsNotification &&
240250
!afterStat.refillsNotification &&
241251
!afterStat.stockMarketNotification &&
252+
!afterStat.forumsSubscriptionsNotification &&
242253
// NOTE: do NOT include here notifications that are outside of the main notification loop
243254
// (e.g. retals, assists, loot), as they don't take into account the "alertsEnabled", but just their own parameter
244255
// Adding them here would cause unnecessary reads for people with "alertsEnabled" if no other specific alerts are active
@@ -269,6 +280,7 @@ export const playersGroup = {
269280
|| afterStat.eventsNotification
270281
|| afterStat.refillsNotification
271282
|| afterStat.stockMarketNotification
283+
|| afterStat.forumsSubscriptionsNotification
272284
// NOTE: do NOT include here notifications that are outside of the main notification loop
273285
// (e.g. retals, assists, loot), as they don't take into account the "alertsEnabled", but just their own parameter
274286
// Adding them here would cause unnecessary reads for people with "alertsEnabled" if no other specific alerts are active

cloud_functions/functions/src/torn_api.ts

+17
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import fetch from 'node-fetch';
2+
import { ForumsApiResponse } from './interfaces/forums_interface';
23

34
export async function getUsersStat(apiKey: string) {
45
const response = await fetch(`https://api.torn.com/user/?selections=profile,bars,travel,icons,cooldowns,newmessages,newevents&key=${apiKey}&comment=PDA-Alerts`);
@@ -13,6 +14,22 @@ export async function getUsersRefills(apiKey: string) {
1314
return data;
1415
}
1516

17+
export async function getUsersForums(apiKey: string): Promise<ForumsApiResponse> {
18+
const response = await fetch("https://api.torn.com/v2/user/forumsubscribedthreads", {
19+
method: "GET",
20+
headers: {
21+
Authorization: `ApiKey ${apiKey}`,
22+
},
23+
});
24+
25+
if (!response.ok) {
26+
throw new Error(`API request failed with status ${response.status}: ${response.statusText}`);
27+
}
28+
29+
return await response.json();
30+
}
31+
32+
1633
export async function checkUserIdKey(apiKey: string, userId: number) {
1734
const response = await fetch(`https://api.torn.com/user/?selections=basic&key=${apiKey}`);
1835
const data = await response.json();

ios/Podfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ target 'Runner' do
3535

3636
# This line needs to be updated with the version or commented out (in which case build will take longer, but nothing else)
3737
# Version at https://github.com/invertase/firestore-ios-sdk-frameworks
38-
pod 'FirebaseFirestore', :git => 'https://github.com/invertase/firestore-ios-sdk-frameworks.git', :tag => '11.4.0'
38+
pod 'FirebaseFirestore', :git => 'https://github.com/invertase/firestore-ios-sdk-frameworks.git', :tag => '11.6.0'
3939
end
4040

4141
post_install do |installer|

0 commit comments

Comments
 (0)