Skip to content

Commit 14155d4

Browse files
alltheseasclaude
andcommitted
Add member_for_more_than_three_years account attribute
Return the new member_for_more_than_three_years boolean in the account attributes response. Uses the same 360-day-year convention as the existing one-year check (3 × 360 = 1080 days). The total membership time is now computed once and reused for both thresholds. Companion to damus-io/damus#3592. Signed-off-by: alltheseas <alltheseas@users.noreply.github.com> Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9ec225e commit 14155d4

2 files changed

Lines changed: 98 additions & 2 deletions

File tree

src/user_management.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,11 @@ function get_account_info_payload(subscriber_number, account, authenticated = fa
179179
const account_active = (account.expiry && current_time() < account.expiry) ? true : false
180180
// We consider one year to be 360 days, to be a bit lenient with users who might have a few days of downtime in their subscription, and make sure everyone who roughly got a year of service gets the benefit during the announcement.
181181
const one_year_in_seconds = 360 * 24 * 60 * 60
182+
const three_years_in_seconds = 3 * one_year_in_seconds
182183
// Performance optimization: We only calculate the total membership time if the account is active
183-
const member_for_more_than_one_year = account_active ? total_active_membership_time(account) > one_year_in_seconds : false
184+
const total_membership_time = account_active ? total_active_membership_time(account) : 0
185+
const member_for_more_than_one_year = total_membership_time > one_year_in_seconds
186+
const member_for_more_than_three_years = total_membership_time > three_years_in_seconds
184187

185188

186189
return {
@@ -192,6 +195,7 @@ function get_account_info_payload(subscriber_number, account, authenticated = fa
192195
testflight_url: (authenticated && account_active) ? process.env.TESTFLIGHT_URL : null,
193196
attributes: {
194197
member_for_more_than_one_year: member_for_more_than_one_year,
198+
member_for_more_than_three_years: member_for_more_than_three_years,
195199
}
196200
}
197201
}

test/router_config.test.js

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const express = require('express');
33
const config_router = require('../src/router_config.js').config_router;
44
const nostr = require('nostr');
55
const current_time = require('../src/utils.js').current_time;
6+
const { get_account_info_payload } = require('../src/user_management.js');
67
const { supertest_client } = require('./controllers/utils.js');
78
const { v4: uuidv4 } = require('uuid')
89

@@ -92,7 +93,8 @@ test('config_router - Account management routes', async (t) => {
9293
active: true,
9394
testflight_url: null,
9495
attributes: {
95-
member_for_more_than_one_year: false
96+
member_for_more_than_one_year: false,
97+
member_for_more_than_three_years: false
9698
}
9799
};
98100
t.same(res.body, expectedData, 'Response should match expected value');
@@ -101,3 +103,93 @@ test('config_router - Account management routes', async (t) => {
101103

102104
t.end();
103105
});
106+
107+
test('get_account_info_payload - membership tenure attributes', async (t) => {
108+
const one_year_in_seconds = 360 * 24 * 60 * 60
109+
110+
t.test('account with < 1080 days returns false for both tenure attributes', async (t) => {
111+
const account = {
112+
pubkey: 'abc123',
113+
created_at: current_time() - 60 * 60 * 24 * 30,
114+
expiry: current_time() + 60 * 60 * 24 * 30,
115+
transactions: [{
116+
type: 'iap',
117+
id: '1',
118+
start_date: current_time() - 60 * 60 * 24 * 30,
119+
end_date: current_time() + 60 * 60 * 24 * 30,
120+
purchased_date: current_time() - 60 * 60 * 24 * 30,
121+
duration: null
122+
}]
123+
}
124+
const payload = get_account_info_payload(1, account)
125+
t.equal(payload.attributes.member_for_more_than_one_year, false)
126+
t.equal(payload.attributes.member_for_more_than_three_years, false)
127+
t.end()
128+
})
129+
130+
t.test('account with > 1080 days returns true for both tenure attributes', async (t) => {
131+
const total_duration = 3 * one_year_in_seconds + 1
132+
const account = {
133+
pubkey: 'abc123',
134+
created_at: current_time() - total_duration,
135+
expiry: current_time() + 60 * 60 * 24 * 30,
136+
transactions: [{
137+
type: 'iap',
138+
id: '1',
139+
start_date: current_time() - total_duration,
140+
end_date: current_time(),
141+
purchased_date: current_time() - total_duration,
142+
duration: null
143+
}]
144+
}
145+
const payload = get_account_info_payload(1, account)
146+
t.equal(payload.attributes.member_for_more_than_one_year, true)
147+
t.equal(payload.attributes.member_for_more_than_three_years, true)
148+
t.end()
149+
})
150+
151+
t.test('account with > 360 days but < 1080 days returns true only for one year', async (t) => {
152+
const total_duration = one_year_in_seconds + 1
153+
const account = {
154+
pubkey: 'abc123',
155+
created_at: current_time() - total_duration,
156+
expiry: current_time() + 60 * 60 * 24 * 30,
157+
transactions: [{
158+
type: 'iap',
159+
id: '1',
160+
start_date: current_time() - total_duration,
161+
end_date: current_time(),
162+
purchased_date: current_time() - total_duration,
163+
duration: null
164+
}]
165+
}
166+
const payload = get_account_info_payload(1, account)
167+
t.equal(payload.attributes.member_for_more_than_one_year, true)
168+
t.equal(payload.attributes.member_for_more_than_three_years, false)
169+
t.end()
170+
})
171+
172+
t.test('inactive account returns false for both tenure attributes', async (t) => {
173+
const total_duration = 3 * one_year_in_seconds + 1
174+
const account = {
175+
pubkey: 'abc123',
176+
created_at: current_time() - total_duration,
177+
expiry: current_time() - 1, // expired
178+
transactions: [{
179+
type: 'iap',
180+
id: '1',
181+
start_date: current_time() - total_duration,
182+
end_date: current_time() - 1,
183+
purchased_date: current_time() - total_duration,
184+
duration: null
185+
}]
186+
}
187+
const payload = get_account_info_payload(1, account)
188+
t.equal(payload.active, false)
189+
t.equal(payload.attributes.member_for_more_than_one_year, false)
190+
t.equal(payload.attributes.member_for_more_than_three_years, false)
191+
t.end()
192+
})
193+
194+
t.end()
195+
});

0 commit comments

Comments
 (0)