0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-10 23:36:14 -05:00

Added members event tables (#12618)

refs https://github.com/TryGhost/Ghost/issues/12602

* Added members_payment_events table

This table will store successful and unsuccessful payment attempts, and
can be used to calculate gross volume over time.

* Added members_login_events table

This table can be used to audit member logins

* Added members_email_change_events table

This table will allow us to store a history of email addresses associated with a member

* Added members_status_events table

This table will allow us to track the change in status over time for members, as well
as calculate aggregates over time, e.g. paid members over time

* Added members_paid_subscription_events

This table will allow us to track subscriptions changes for members, as well as 
calculating MRR over time
This commit is contained in:
Fabien 'egg' O'Carroll 2021-02-11 10:54:30 +00:00 committed by GitHub
parent 8e05a375ad
commit 601d135b43
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 90 additions and 3 deletions

View file

@ -0,0 +1,6 @@
const {addTable} = require('../../utils');
module.exports = addTable('members_login_events', {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
member_id: {type: 'string', maxlength: 24, nullable: false, references: 'members.id', cascadeDelete: true},
created_at: {type: 'dateTime', nullable: false}
});

View file

@ -0,0 +1,8 @@
const {addTable} = require('../../utils');
module.exports = addTable('members_email_change_events', {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
member_id: {type: 'string', maxlength: 24, nullable: false, references: 'members.id', cascadeDelete: true},
email: {type: 'string', maxlength: 191, nullable: false, unique: false, validations: {isEmail: true}},
created_at: {type: 'dateTime', nullable: false}
});

View file

@ -0,0 +1,8 @@
const {addTable} = require('../../utils');
module.exports = addTable('members_status_events', {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
member_id: {type: 'string', maxlength: 24, nullable: false, references: 'members.id', cascadeDelete: true},
status: {type: 'string', maxlength: 50, nullable: false},
created_at: {type: 'dateTime', nullable: false}
});

View file

@ -0,0 +1,12 @@
const {addTable} = require('../../utils');
module.exports = addTable('members_paid_subscription_events', {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
member_id: {type: 'string', maxlength: 24, nullable: false, references: 'members.id', cascadeDelete: true},
from_plan: {type: 'string', maxlength: 50, nullable: true},
to_plan: {type: 'string', maxlength: 50, nullable: true},
currency: {type: 'string', maxLength: 3, nullable: false},
source: {type: 'string', maxlength: 50, nullable: false},
mrr_delta: {type: 'integer', nullable: false},
created_at: {type: 'dateTime', nullable: false}
});

View file

@ -0,0 +1,10 @@
const {addTable} = require('../../utils');
module.exports = addTable('members_payment_events', {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
member_id: {type: 'string', maxlength: 24, nullable: false, references: 'members.id', cascadeDelete: true},
amount: {type: 'integer', nullable: false},
currency: {type: 'string', maxLength: 3, nullable: false},
source: {type: 'string', maxlength: 50, nullable: false},
created_at: {type: 'dateTime', nullable: false}
});

View file

@ -340,7 +340,7 @@ module.exports = {
email: {type: 'string', maxlength: 191, nullable: false, unique: true, validations: {isEmail: true}},
status: {
type: 'string', maxlength: 50, nullable: false, defaultTo: 'free', validations: {
isIn: [['free', 'paid']]
isIn: [['free', 'paid', 'comped']]
}
},
name: {type: 'string', maxlength: 191, nullable: true},
@ -355,6 +355,49 @@ module.exports = {
updated_at: {type: 'dateTime', nullable: true},
updated_by: {type: 'string', maxlength: 24, nullable: true}
},
members_payment_events: {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
member_id: {type: 'string', maxlength: 24, nullable: false, references: 'members.id', cascadeDelete: true},
amount: {type: 'integer', nullable: false},
currency: {type: 'string', maxLength: 3, nullable: false},
source: {type: 'string', maxlength: 50, nullable: false},
created_at: {type: 'dateTime', nullable: false}
},
members_login_events: {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
member_id: {type: 'string', maxlength: 24, nullable: false, references: 'members.id', cascadeDelete: true},
created_at: {type: 'dateTime', nullable: false}
},
members_email_change_events: {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
member_id: {type: 'string', maxlength: 24, nullable: false, references: 'members.id', cascadeDelete: true},
email: {type: 'string', maxlength: 191, nullable: false, unique: false, validations: {isEmail: true}},
created_at: {type: 'dateTime', nullable: false}
},
members_status_events: {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
member_id: {type: 'string', maxlength: 24, nullable: false, references: 'members.id', cascadeDelete: true},
status: {
type: 'string', maxlength: 50, nullable: false, validations: {
isIn: [['free', 'paid', 'comped']]
}
},
created_at: {type: 'dateTime', nullable: false}
},
members_paid_subscription_events: {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
member_id: {type: 'string', maxlength: 24, nullable: false, references: 'members.id', cascadeDelete: true},
from_plan: {type: 'string', maxlength: 50, nullable: true},
to_plan: {type: 'string', maxlength: 50, nullable: true},
currency: {type: 'string', maxLength: 3, nullable: false},
source: {
type: 'string', maxlength: 50, nullable: false, validations: {
isIn: [['stripe']]
}
},
mrr_delta: {type: 'integer', nullable: false},
created_at: {type: 'dateTime', nullable: false}
},
labels: {
id: {type: 'string', maxlength: 24, nullable: false, primary: true},
name: {type: 'string', maxlength: 191, nullable: false, unique: true},

View file

@ -47,7 +47,7 @@ describe('DB API', function () {
const jsonResponse = res.body;
should.exist(jsonResponse.db);
jsonResponse.db.should.have.length(1);
Object.keys(jsonResponse.db[0].data).length.should.eql(29);
Object.keys(jsonResponse.db[0].data).length.should.eql(34);
});
it('Can import a JSON database', async function () {

View file

@ -32,7 +32,7 @@ const defaultSettings = require('../../../../core/server/data/schema/default-set
*/
describe('DB version integrity', function () {
// Only these variables should need updating
const currentSchemaHash = '7aa70515d52a2d55805ebe272e491db7';
const currentSchemaHash = '091a6cf44f3eb51115f0e1e422db4db6';
const currentFixturesHash = '370d0da0ab7c45050b2ff30bce8896ba';
const currentSettingsHash = '162f9294cc427eb32bc0577006c385ce';
const currentRoutesHash = '3d180d52c663d173a6be791ef411ed01';