@atproto/ozone
Version:
Backend service for moderating the Bluesky network.
179 lines • 6.36 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SafelinkRuleService = void 0;
const xrpc_server_1 = require("@atproto/xrpc-server");
class SafelinkRuleService {
constructor(db) {
Object.defineProperty(this, "db", {
enumerable: true,
configurable: true,
writable: true,
value: db
});
}
static creator() {
return (db) => new SafelinkRuleService(db);
}
formatEvent(event) {
return {
id: event.id,
eventType: event.eventType,
url: event.url,
pattern: event.pattern,
action: event.action,
reason: event.reason,
createdBy: event.createdBy,
createdAt: new Date(event.createdAt).toISOString(),
comment: event.comment || undefined,
};
}
async addRule({ url, pattern, action, reason, createdBy, comment, }) {
const existingRule = await this.getActiveRule(url, pattern);
if (existingRule) {
throw new xrpc_server_1.InvalidRequestError('A rule for this URL/domain already exists', 'RuleAlreadyExists');
}
const now = new Date().toISOString();
const rule = {
url,
pattern,
action,
reason,
createdBy,
comment: comment || null,
createdAt: now,
};
return await this.db.transaction(async (txn) => {
const event = await txn.db
.insertInto('safelink_event')
.values({
eventType: 'addRule',
...rule,
})
.returningAll()
.executeTakeFirstOrThrow();
await txn.db
.insertInto('safelink_rule')
.values({ ...rule, updatedAt: now })
.execute();
return event;
});
}
async updateRule({ url, pattern, action, reason, createdBy, comment, }) {
const existingRule = await this.getActiveRule(url, pattern);
if (!existingRule) {
throw new xrpc_server_1.InvalidRequestError('No active rule found for this URL/domain', 'RuleNotFound');
}
const now = new Date().toISOString();
const rule = {
action,
reason,
createdBy,
comment: comment || null,
};
return await this.db.transaction(async (txn) => {
const event = await txn.db
.insertInto('safelink_event')
.values({
createdAt: now,
url: existingRule.url,
pattern: existingRule.pattern,
eventType: 'updateRule',
...rule,
})
.returningAll()
.executeTakeFirstOrThrow();
await txn.db
.updateTable('safelink_rule')
.set(rule)
.where('url', '=', existingRule.url)
.where('pattern', '=', existingRule.pattern)
.execute();
return event;
});
}
async removeRule({ url, pattern, createdBy, comment, }) {
const existingRule = await this.getActiveRule(url, pattern);
if (!existingRule) {
throw new xrpc_server_1.InvalidRequestError('No active rule found for this URL/domain', 'RuleNotFound');
}
return await this.db.transaction(async (txn) => {
const event = await txn.db
.insertInto('safelink_event')
.values({
eventType: 'removeRule',
url,
pattern,
action: existingRule.action,
reason: existingRule.reason,
createdBy,
comment: comment || null,
createdAt: new Date().toISOString(),
})
.returningAll()
.executeTakeFirstOrThrow();
await txn.db
.deleteFrom('safelink_rule')
.where('url', '=', url)
.where('pattern', '=', pattern)
.execute();
return event;
});
}
async getActiveRule(url, pattern) {
const rule = await this.db.db
.selectFrom('safelink_rule')
.selectAll()
.where('url', '=', url)
.where('pattern', '=', pattern)
.executeTakeFirst();
if (!rule) {
return null;
}
return rule;
}
async getActiveRules({ cursor, limit = 50, urls, patternType, actions, reason, createdBy, direction = 'desc', } = {}) {
let query = this.db.db.selectFrom('safelink_rule').selectAll();
if (urls && urls.length > 0) {
query = query.where('url', 'in', urls);
}
if (patternType) {
query = query.where('pattern', '=', patternType);
}
if (actions && actions.length > 0) {
query = query.where('action', 'in', actions);
}
if (reason) {
query = query.where('reason', '=', reason);
}
if (createdBy) {
query = query.where('createdBy', '=', createdBy);
}
if (cursor) {
query = query.where('id', direction === 'asc' ? '>' : '<', parseInt(cursor, 10));
}
const rules = await query.orderBy('id', direction).limit(limit).execute();
return {
rules,
cursor: rules.at(-1)?.id?.toString(),
};
}
async queryEvents({ cursor, limit = 50, urls, patternType, direction = 'desc', } = {}) {
let query = this.db.db.selectFrom('safelink_event').selectAll();
if (urls && urls.length > 0) {
query = query.where('url', 'in', urls);
}
if (patternType) {
query = query.where('pattern', '=', patternType);
}
if (cursor) {
query = query.where('id', direction === 'asc' ? '>' : '<', parseInt(cursor, 10));
}
const events = await query.orderBy('id', direction).limit(limit).execute();
return {
events,
cursor: events.at(-1)?.id?.toString(),
};
}
}
exports.SafelinkRuleService = SafelinkRuleService;
//# sourceMappingURL=service.js.map