Merge pull request #1759 from albertgasset/MOBILE-2842

Mobile 2842
main
Juan Leyva 2019-02-08 14:11:38 +01:00 committed by GitHub
commit e8e7099a1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1895 additions and 1494 deletions

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreSite } from '@classes/site'; import { CoreSite } from '@classes/site';
import { CoreCoursesProvider } from '@core/courses/providers/courses'; import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
@ -38,95 +38,99 @@ export class AddonCalendarProvider {
// Variables for database. // Variables for database.
static EVENTS_TABLE = 'addon_calendar_events'; static EVENTS_TABLE = 'addon_calendar_events';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'AddonCalendarProvider',
name: AddonCalendarProvider.EVENTS_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'id', name: AddonCalendarProvider.EVENTS_TABLE,
type: 'INTEGER', columns: [
primaryKey: true {
}, name: 'id',
{ type: 'INTEGER',
name: 'notificationtime', primaryKey: true
type: 'INTEGER' },
}, {
{ name: 'notificationtime',
name: 'name', type: 'INTEGER'
type: 'TEXT', },
notNull: true {
}, name: 'name',
{ type: 'TEXT',
name: 'description', notNull: true
type: 'TEXT' },
}, {
{ name: 'description',
name: 'format', type: 'TEXT'
type: 'INTEGER' },
}, {
{ name: 'format',
name: 'eventtype', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'eventtype',
name: 'courseid', type: 'TEXT'
type: 'INTEGER' },
}, {
{ name: 'courseid',
name: 'timestart', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'timestart',
name: 'timeduration', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'timeduration',
name: 'categoryid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'categoryid',
name: 'groupid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'groupid',
name: 'userid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'userid',
name: 'instance', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'instance',
name: 'modulename', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'modulename',
name: 'timemodified', type: 'TEXT'
type: 'INTEGER' },
}, {
{ name: 'timemodified',
name: 'repeatid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'repeatid',
name: 'visible', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'visible',
name: 'uuid', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'uuid',
name: 'sequence', type: 'TEXT'
type: 'INTEGER' },
}, {
{ name: 'sequence',
name: 'subscriptionid', type: 'INTEGER'
type: 'INTEGER' },
} {
] name: 'subscriptionid',
} type: 'INTEGER'
]; }
]
}
]
};
protected logger; protected logger;
@ -134,7 +138,7 @@ export class AddonCalendarProvider {
private coursesProvider: CoreCoursesProvider, private timeUtils: CoreTimeUtilsProvider, private coursesProvider: CoreCoursesProvider, private timeUtils: CoreTimeUtilsProvider,
private localNotificationsProvider: CoreLocalNotificationsProvider, private configProvider: CoreConfigProvider) { private localNotificationsProvider: CoreLocalNotificationsProvider, private configProvider: CoreConfigProvider) {
this.logger = logger.getInstance('AddonCalendarProvider'); this.logger = logger.getInstance('AddonCalendarProvider');
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreAppProvider } from '@providers/app'; import { CoreAppProvider } from '@providers/app';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
@ -29,65 +29,69 @@ export class AddonMessagesOfflineProvider {
// Variables for database. // Variables for database.
static MESSAGES_TABLE = 'addon_messages_offline_messages'; // When group messaging isn't available or a new conversation starts. static MESSAGES_TABLE = 'addon_messages_offline_messages'; // When group messaging isn't available or a new conversation starts.
static CONVERSATION_MESSAGES_TABLE = 'addon_messages_offline_conversation_messages'; // Conversation messages. static CONVERSATION_MESSAGES_TABLE = 'addon_messages_offline_conversation_messages'; // Conversation messages.
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'AddonMessagesOfflineProvider',
name: AddonMessagesOfflineProvider.MESSAGES_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'touserid', name: AddonMessagesOfflineProvider.MESSAGES_TABLE,
type: 'INTEGER' columns: [
}, {
{ name: 'touserid',
name: 'useridfrom', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'useridfrom',
name: 'smallmessage', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'smallmessage',
name: 'timecreated', type: 'TEXT'
type: 'INTEGER' },
}, {
{ name: 'timecreated',
name: 'deviceoffline', // If message was stored because device was offline. type: 'INTEGER'
type: 'INTEGER' },
} {
], name: 'deviceoffline', // If message was stored because device was offline.
primaryKeys: ['touserid', 'smallmessage', 'timecreated'] type: 'INTEGER'
}, }
{ ],
name: AddonMessagesOfflineProvider.CONVERSATION_MESSAGES_TABLE, primaryKeys: ['touserid', 'smallmessage', 'timecreated']
columns: [ },
{ {
name: 'conversationid', name: AddonMessagesOfflineProvider.CONVERSATION_MESSAGES_TABLE,
type: 'INTEGER' columns: [
}, {
{ name: 'conversationid',
name: 'text', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'text',
name: 'timecreated', type: 'TEXT'
type: 'INTEGER' },
}, {
{ name: 'timecreated',
name: 'deviceoffline', // If message was stored because device was offline. type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'deviceoffline', // If message was stored because device was offline.
name: 'conversation', // Data about the conversation. type: 'INTEGER'
type: 'TEXT' },
} {
], name: 'conversation', // Data about the conversation.
primaryKeys: ['conversationid', 'text', 'timecreated'] type: 'TEXT'
} }
]; ],
primaryKeys: ['conversationid', 'text', 'timecreated']
}
]
};
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private appProvider: CoreAppProvider, constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private appProvider: CoreAppProvider,
private textUtils: CoreTextUtilsProvider) { private textUtils: CoreTextUtilsProvider) {
this.logger = logger.getInstance('AddonMessagesOfflineProvider'); this.logger = logger.getInstance('AddonMessagesOfflineProvider');
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -15,7 +15,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreFileProvider } from '@providers/file'; import { CoreFileProvider } from '@providers/file';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
@ -30,105 +30,109 @@ export class AddonModAssignOfflineProvider {
// Variables for database. // Variables for database.
static SUBMISSIONS_TABLE = 'addon_mod_assign_submissions'; static SUBMISSIONS_TABLE = 'addon_mod_assign_submissions';
static SUBMISSIONS_GRADES_TABLE = 'addon_mod_assign_submissions_grading'; static SUBMISSIONS_GRADES_TABLE = 'addon_mod_assign_submissions_grading';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'AddonModAssignOfflineProvider',
name: AddonModAssignOfflineProvider.SUBMISSIONS_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'assignid', name: AddonModAssignOfflineProvider.SUBMISSIONS_TABLE,
type: 'INTEGER' columns: [
}, {
{ name: 'assignid',
name: 'courseid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'courseid',
name: 'userid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'userid',
name: 'plugindata', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'plugindata',
name: 'onlinetimemodified', type: 'TEXT'
type: 'INTEGER' },
}, {
{ name: 'onlinetimemodified',
name: 'timecreated', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'timecreated',
name: 'timemodified', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'timemodified',
name: 'submitted', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'submitted',
name: 'submissionstatement', type: 'INTEGER'
type: 'INTEGER' },
} {
], name: 'submissionstatement',
primaryKeys: ['assignid', 'userid'] type: 'INTEGER'
}, }
{ ],
name: AddonModAssignOfflineProvider.SUBMISSIONS_GRADES_TABLE, primaryKeys: ['assignid', 'userid']
columns: [ },
{ {
name: 'assignid', name: AddonModAssignOfflineProvider.SUBMISSIONS_GRADES_TABLE,
type: 'INTEGER' columns: [
}, {
{ name: 'assignid',
name: 'courseid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'courseid',
name: 'userid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'userid',
name: 'grade', type: 'INTEGER'
type: 'REAL' },
}, {
{ name: 'grade',
name: 'attemptnumber', type: 'REAL'
type: 'INTEGER' },
}, {
{ name: 'attemptnumber',
name: 'addattempt', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'addattempt',
name: 'workflowstate', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'workflowstate',
name: 'applytoall', type: 'TEXT'
type: 'INTEGER' },
}, {
{ name: 'applytoall',
name: 'outcomes', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'outcomes',
name: 'plugindata', type: 'TEXT'
type: 'TEXT' },
}, {
{ name: 'plugindata',
name: 'timemodified', type: 'TEXT'
type: 'INTEGER' },
} {
], name: 'timemodified',
primaryKeys: ['assignid', 'userid'] type: 'INTEGER'
} }
]; ],
primaryKeys: ['assignid', 'userid']
}
]
};
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private textUtils: CoreTextUtilsProvider, constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private textUtils: CoreTextUtilsProvider,
private fileProvider: CoreFileProvider, private timeUtils: CoreTimeUtilsProvider) { private fileProvider: CoreFileProvider, private timeUtils: CoreTimeUtilsProvider) {
this.logger = logger.getInstance('AddonModAssignOfflineProvider'); this.logger = logger.getInstance('AddonModAssignOfflineProvider');
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
/** /**
* Service to handle offline choices. * Service to handle offline choices.
@ -23,45 +23,50 @@ export class AddonModChoiceOfflineProvider {
// Variables for database. // Variables for database.
static CHOICE_TABLE = 'addon_mod_choice_responses'; static CHOICE_TABLE = 'addon_mod_choice_responses';
protected tablesSchema = [
{ protected siteSchema: CoreSiteSchema = {
name: AddonModChoiceOfflineProvider.CHOICE_TABLE, name: 'AddonModChoiceOfflineProvider',
columns: [ version: 1,
{ tables: [
name: 'choiceid', {
type: 'INTEGER' name: AddonModChoiceOfflineProvider.CHOICE_TABLE,
}, columns: [
{ {
name: 'name', name: 'choiceid',
type: 'TEXT' type: 'INTEGER'
}, },
{ {
name: 'courseid', name: 'name',
type: 'INTEGER' type: 'TEXT'
}, },
{ {
name: 'userid', name: 'courseid',
type: 'INTEGER' type: 'INTEGER'
}, },
{ {
name: 'responses', name: 'userid',
type: 'TEXT' type: 'INTEGER'
}, },
{ {
name: 'deleting', name: 'responses',
type: 'INTEGER' type: 'TEXT'
}, },
{ {
name: 'timecreated', name: 'deleting',
type: 'INTEGER' type: 'INTEGER'
} },
], {
primaryKeys: ['choiceid', 'userid'] name: 'timecreated',
} type: 'INTEGER'
]; }
],
primaryKeys: ['choiceid', 'userid']
}
]
};
constructor(private sitesProvider: CoreSitesProvider) { constructor(private sitesProvider: CoreSitesProvider) {
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -14,10 +14,11 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreFileProvider } from '@providers/file'; import { CoreFileProvider } from '@providers/file';
import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader'; import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
import { SQLiteDB } from '@classes/sqlitedb';
/** /**
* Service to handle Offline data. * Service to handle Offline data.
@ -28,48 +29,67 @@ export class AddonModDataOfflineProvider {
protected logger; protected logger;
// Variables for database. // Variables for database.
static DATA_ENTRY_TABLE = 'addon_mod_data_entry'; static DATA_ENTRY_TABLE = 'addon_mod_data_entry_1';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'AddonModDataOfflineProvider',
name: AddonModDataOfflineProvider.DATA_ENTRY_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'dataid', name: AddonModDataOfflineProvider.DATA_ENTRY_TABLE,
type: 'INTEGER' columns: [
}, {
{ name: 'dataid',
name: 'courseid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'courseid',
name: 'groupid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'groupid',
name: 'action', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'action',
name: 'entryid', type: 'TEXT'
type: 'INTEGER' },
}, {
{ name: 'entryid',
name: 'fields', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'fields',
name: 'timemodified', type: 'TEXT'
type: 'INTEGER' },
} {
], name: 'timemodified',
primaryKeys: ['dataid', 'entryid'] type: 'INTEGER'
}
],
primaryKeys: ['dataid', 'entryid', 'action']
}
],
migrate(db: SQLiteDB, oldVersion: number): Promise<any> | void {
if (oldVersion == 0) {
// Move the records from the old table.
const newTable = AddonModDataOfflineProvider.DATA_ENTRY_TABLE;
const oldTable = 'addon_mod_data_entry';
return db.tableExists(oldTable).then(() => {
return db.insertRecordsFrom(newTable, oldTable).then(() => {
return db.dropTable(oldTable);
});
}).catch(() => {
// Old table does not exist, ignore.
});
}
} }
]; };
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private textUtils: CoreTextUtilsProvider, constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private textUtils: CoreTextUtilsProvider,
private fileProvider: CoreFileProvider, private fileUploaderProvider: CoreFileUploaderProvider) { private fileProvider: CoreFileProvider, private fileUploaderProvider: CoreFileUploaderProvider) {
this.logger = logger.getInstance('AddonModDataOfflineProvider'); this.logger = logger.getInstance('AddonModDataOfflineProvider');
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
@ -28,39 +28,43 @@ export class AddonModFeedbackOfflineProvider {
// Variables for database. // Variables for database.
static FEEDBACK_TABLE = 'addon_mod_feedback_answers'; static FEEDBACK_TABLE = 'addon_mod_feedback_answers';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'AddonModFeedbackOfflineProvider',
name: AddonModFeedbackOfflineProvider.FEEDBACK_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'feedbackid', name: AddonModFeedbackOfflineProvider.FEEDBACK_TABLE,
type: 'INTEGER' columns: [
}, {
{ name: 'feedbackid',
name: 'page', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'page',
name: 'courseid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'courseid',
name: 'responses', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'responses',
name: 'timemodified', type: 'TEXT'
type: 'INTEGER' },
} {
], name: 'timemodified',
primaryKeys: ['feedbackid', 'page'] type: 'INTEGER'
} }
]; ],
primaryKeys: ['feedbackid', 'page']
}
]
};
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider,
private textUtils: CoreTextUtilsProvider, private timeUtils: CoreTimeUtilsProvider) { private textUtils: CoreTextUtilsProvider, private timeUtils: CoreTimeUtilsProvider) {
this.logger = logger.getInstance('AddonModFeedbackOfflineProvider'); this.logger = logger.getInstance('AddonModFeedbackOfflineProvider');
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreFileProvider } from '@providers/file'; import { CoreFileProvider } from '@providers/file';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
/** /**
@ -27,101 +27,105 @@ export class AddonModForumOfflineProvider {
static DISCUSSIONS_TABLE = 'addon_mod_forum_discussions'; static DISCUSSIONS_TABLE = 'addon_mod_forum_discussions';
static REPLIES_TABLE = 'addon_mod_forum_replies'; static REPLIES_TABLE = 'addon_mod_forum_replies';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'AddonModForumOfflineProvider',
name: AddonModForumOfflineProvider.DISCUSSIONS_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'forumid', name: AddonModForumOfflineProvider.DISCUSSIONS_TABLE,
type: 'INTEGER', columns: [
}, {
{ name: 'forumid',
name: 'name', type: 'INTEGER',
type: 'TEXT', },
}, {
{ name: 'name',
name: 'courseid', type: 'TEXT',
type: 'INTEGER', },
}, {
{ name: 'courseid',
name: 'subject', type: 'INTEGER',
type: 'TEXT', },
}, {
{ name: 'subject',
name: 'message', type: 'TEXT',
type: 'TEXT', },
}, {
{ name: 'message',
name: 'options', type: 'TEXT',
type: 'TEXT', },
}, {
{ name: 'options',
name: 'groupid', type: 'TEXT',
type: 'INTEGER', },
}, {
{ name: 'groupid',
name: 'userid', type: 'INTEGER',
type: 'INTEGER', },
}, {
{ name: 'userid',
name: 'timecreated', type: 'INTEGER',
type: 'INTEGER', },
} {
], name: 'timecreated',
primaryKeys: ['forumid', 'userid', 'timecreated'] type: 'INTEGER',
}, }
{ ],
name: AddonModForumOfflineProvider.REPLIES_TABLE, primaryKeys: ['forumid', 'userid', 'timecreated']
columns: [ },
{ {
name: 'postid', name: AddonModForumOfflineProvider.REPLIES_TABLE,
type: 'INTEGER', columns: [
}, {
{ name: 'postid',
name: 'discussionid', type: 'INTEGER',
type: 'INTEGER', },
}, {
{ name: 'discussionid',
name: 'forumid', type: 'INTEGER',
type: 'INTEGER', },
}, {
{ name: 'forumid',
name: 'name', type: 'INTEGER',
type: 'TEXT', },
}, {
{ name: 'name',
name: 'courseid', type: 'TEXT',
type: 'INTEGER', },
}, {
{ name: 'courseid',
name: 'subject', type: 'INTEGER',
type: 'TEXT', },
}, {
{ name: 'subject',
name: 'message', type: 'TEXT',
type: 'TEXT', },
}, {
{ name: 'message',
name: 'options', type: 'TEXT',
type: 'TEXT', },
}, {
{ name: 'options',
name: 'userid', type: 'TEXT',
type: 'INTEGER', },
}, {
{ name: 'userid',
name: 'timecreated', type: 'INTEGER',
type: 'INTEGER', },
} {
], name: 'timecreated',
primaryKeys: ['postid', 'userid'] type: 'INTEGER',
} }
]; ],
primaryKeys: ['postid', 'userid']
}
]
};
constructor(private fileProvider: CoreFileProvider, constructor(private fileProvider: CoreFileProvider,
private sitesProvider: CoreSitesProvider, private sitesProvider: CoreSitesProvider,
private textUtils: CoreTextUtilsProvider) { private textUtils: CoreTextUtilsProvider) {
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreFileProvider } from '@providers/file'; import { CoreFileProvider } from '@providers/file';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
@ -27,56 +27,60 @@ export class AddonModGlossaryOfflineProvider {
// Variables for database. // Variables for database.
static ENTRIES_TABLE = 'addon_mod_glossary_entrues'; static ENTRIES_TABLE = 'addon_mod_glossary_entrues';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'AddonModGlossaryOfflineProvider',
name: AddonModGlossaryOfflineProvider.ENTRIES_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'glossaryid', name: AddonModGlossaryOfflineProvider.ENTRIES_TABLE,
type: 'INTEGER', columns: [
}, {
{ name: 'glossaryid',
name: 'courseid', type: 'INTEGER',
type: 'INTEGER', },
}, {
{ name: 'courseid',
name: 'concept', type: 'INTEGER',
type: 'TEXT', },
}, {
{ name: 'concept',
name: 'definition', type: 'TEXT',
type: 'TEXT', },
}, {
{ name: 'definition',
name: 'definitionformat', type: 'TEXT',
type: 'TEXT', },
}, {
{ name: 'definitionformat',
name: 'userid', type: 'TEXT',
type: 'INTEGER', },
}, {
{ name: 'userid',
name: 'timecreated', type: 'INTEGER',
type: 'INTEGER', },
}, {
{ name: 'timecreated',
name: 'options', type: 'INTEGER',
type: 'TEXT', },
}, {
{ name: 'options',
name: 'attachments', type: 'TEXT',
type: 'TEXT', },
}, {
], name: 'attachments',
primaryKeys: ['glossaryid', 'concept', 'timecreated'] type: 'TEXT',
} },
]; ],
primaryKeys: ['glossaryid', 'concept', 'timecreated']
}
]
};
constructor(private fileProvider: CoreFileProvider, constructor(private fileProvider: CoreFileProvider,
private sitesProvider: CoreSitesProvider, private sitesProvider: CoreSitesProvider,
private textUtils: CoreTextUtilsProvider, private textUtils: CoreTextUtilsProvider,
private utils: CoreUtilsProvider) { private utils: CoreUtilsProvider) {
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
@ -31,103 +31,108 @@ export class AddonModLessonOfflineProvider {
// Variables for database. We use lowercase in the names to match the WS responses. // Variables for database. We use lowercase in the names to match the WS responses.
static RETAKES_TABLE = 'addon_mod_lesson_retakes'; static RETAKES_TABLE = 'addon_mod_lesson_retakes';
static PAGE_ATTEMPTS_TABLE = 'addon_mod_lesson_page_attempts'; static PAGE_ATTEMPTS_TABLE = 'addon_mod_lesson_page_attempts';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'AddonModLessonOfflineProvider',
name: AddonModLessonOfflineProvider.RETAKES_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'lessonid', name: AddonModLessonOfflineProvider.RETAKES_TABLE,
type: 'INTEGER', columns: [
primaryKey: true // Only 1 offline retake per lesson. {
}, name: 'lessonid',
{ type: 'INTEGER',
name: 'retake', // Retake number. primaryKey: true // Only 1 offline retake per lesson.
type: 'INTEGER', },
notNull: true {
}, name: 'retake', // Retake number.
{ type: 'INTEGER',
name: 'courseid', notNull: true
type: 'INTEGER' },
}, {
{ name: 'courseid',
name: 'finished', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'finished',
name: 'outoftime', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'outoftime',
name: 'timemodified', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'timemodified',
name: 'lastquestionpage', type: 'INTEGER'
type: 'INTEGER' },
}, {
] name: 'lastquestionpage',
}, type: 'INTEGER'
{ },
name: AddonModLessonOfflineProvider.PAGE_ATTEMPTS_TABLE, ]
columns: [ },
{ {
name: 'lessonid', name: AddonModLessonOfflineProvider.PAGE_ATTEMPTS_TABLE,
type: 'INTEGER', columns: [
notNull: true {
}, name: 'lessonid',
{ type: 'INTEGER',
name: 'retake', // Retake number. notNull: true
type: 'INTEGER', },
notNull: true {
}, name: 'retake', // Retake number.
{ type: 'INTEGER',
name: 'pageid', notNull: true
type: 'INTEGER', },
notNull: true {
}, name: 'pageid',
{ type: 'INTEGER',
name: 'timemodified', notNull: true
type: 'INTEGER', },
notNull: true {
}, name: 'timemodified',
{ type: 'INTEGER',
name: 'courseid', notNull: true
type: 'INTEGER' },
}, {
{ name: 'courseid',
name: 'data', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'data',
name: 'type', type: 'TEXT'
type: 'INTEGER' },
}, {
{ name: 'type',
name: 'newpageid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'newpageid',
name: 'correct', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'correct',
name: 'answerid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'answerid',
name: 'useranswer', type: 'INTEGER'
type: 'TEXT' },
}, {
], name: 'useranswer',
primaryKeys: ['lessonid', 'retake', 'pageid', 'timemodified'] // A user can attempt several times per page and retake. type: 'TEXT'
} },
]; ],
// A user can attempt several times per page and retake.
primaryKeys: ['lessonid', 'retake', 'pageid', 'timemodified']
}
]
};
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private timeUtils: CoreTimeUtilsProvider, constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private timeUtils: CoreTimeUtilsProvider,
private textUtils: CoreTextUtilsProvider, private utils: CoreUtilsProvider) { private textUtils: CoreTextUtilsProvider, private utils: CoreUtilsProvider) {
this.logger = logger.getInstance('AddonModLessonOfflineProvider'); this.logger = logger.getInstance('AddonModLessonOfflineProvider');
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -17,7 +17,7 @@ import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app'; import { CoreAppProvider } from '@providers/app';
import { CoreEventsProvider } from '@providers/events'; import { CoreEventsProvider } from '@providers/events';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreSyncProvider } from '@providers/sync'; import { CoreSyncProvider } from '@providers/sync';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
@ -58,25 +58,31 @@ export class AddonModLessonSyncProvider extends CoreSyncBaseProvider {
// Variables for database. // Variables for database.
static RETAKES_FINISHED_TABLE = 'addon_mod_lesson_retakes_finished_sync'; static RETAKES_FINISHED_TABLE = 'addon_mod_lesson_retakes_finished_sync';
protected tablesSchema = { protected siteSchema: CoreSiteSchema = {
name: AddonModLessonSyncProvider.RETAKES_FINISHED_TABLE, name: 'AddonModLessonSyncProvider',
columns: [ version: 1,
tables: [
{ {
name: 'lessonid', name: AddonModLessonSyncProvider.RETAKES_FINISHED_TABLE,
type: 'INTEGER', columns: [
primaryKey: true {
}, name: 'lessonid',
{ type: 'INTEGER',
name: 'retake', primaryKey: true
type: 'INTEGER' },
}, {
{ name: 'retake',
name: 'pageid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'pageid',
name: 'timefinished', type: 'INTEGER'
type: 'INTEGER' },
{
name: 'timefinished',
type: 'INTEGER'
}
]
} }
] ]
}; };
@ -93,7 +99,7 @@ export class AddonModLessonSyncProvider extends CoreSyncBaseProvider {
this.componentTranslate = courseProvider.translateModuleName('lesson'); this.componentTranslate = courseProvider.translateModuleName('lesson');
this.sitesProvider.createTableFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -15,7 +15,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
@ -155,21 +155,27 @@ export class AddonModLessonProvider {
// Variables for database. // Variables for database.
static PASSWORD_TABLE = 'addon_mod_lesson_password'; static PASSWORD_TABLE = 'addon_mod_lesson_password';
protected tablesSchema = { protected siteSchema: CoreSiteSchema = {
name: AddonModLessonProvider.PASSWORD_TABLE, name: 'AddonModLessonProvider',
columns: [ version: 1,
tables: [
{ {
name: 'lessonid', name: AddonModLessonProvider.PASSWORD_TABLE,
type: 'INTEGER', columns: [
primaryKey: true {
}, name: 'lessonid',
{ type: 'INTEGER',
name: 'password', primaryKey: true
type: 'TEXT' },
}, {
{ name: 'password',
name: 'timemodified', type: 'TEXT'
type: 'INTEGER' },
{
name: 'timemodified',
type: 'INTEGER'
}
]
} }
] ]
}; };
@ -182,7 +188,7 @@ export class AddonModLessonProvider {
private lessonOfflineProvider: AddonModLessonOfflineProvider) { private lessonOfflineProvider: AddonModLessonOfflineProvider) {
this.logger = logger.getInstance('AddonModLessonProvider'); this.logger = logger.getInstance('AddonModLessonProvider');
this.sitesProvider.createTableFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -14,7 +14,7 @@
// limitations under the License. // limitations under the License.
import { Injectable, Injector } from '@angular/core'; import { Injectable, Injector } from '@angular/core';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { AddonModQuizAccessRuleHandler } from '../../../providers/access-rules-delegate'; import { AddonModQuizAccessRuleHandler } from '../../../providers/access-rules-delegate';
import { AddonModQuizAccessPasswordComponent } from '../component/password'; import { AddonModQuizAccessPasswordComponent } from '../component/password';
@ -25,21 +25,27 @@ import { AddonModQuizAccessPasswordComponent } from '../component/password';
export class AddonModQuizAccessPasswordHandler implements AddonModQuizAccessRuleHandler { export class AddonModQuizAccessPasswordHandler implements AddonModQuizAccessRuleHandler {
// Variables for database. // Variables for database.
static PASSWORD_TABLE = 'addon_mod_quiz_access_password'; static PASSWORD_TABLE = 'addon_mod_quiz_access_password';
protected tableSchema = { protected siteSchema: CoreSiteSchema = {
name: AddonModQuizAccessPasswordHandler.PASSWORD_TABLE, name: 'AddonModQuizAccessPasswordHandler',
columns: [ version: 1,
tables: [
{ {
name: 'id', name: AddonModQuizAccessPasswordHandler.PASSWORD_TABLE,
type: 'INTEGER', columns: [
primaryKey: true {
}, name: 'id',
{ type: 'INTEGER',
name: 'password', primaryKey: true
type: 'TEXT' },
}, {
{ name: 'password',
name: 'timemodified', type: 'TEXT'
type: 'INTEGER' },
{
name: 'timemodified',
type: 'INTEGER'
}
]
} }
] ]
}; };
@ -48,7 +54,7 @@ export class AddonModQuizAccessPasswordHandler implements AddonModQuizAccessRule
ruleName = 'quizaccess_password'; ruleName = 'quizaccess_password';
constructor(private sitesProvider: CoreSitesProvider) { constructor(private sitesProvider: CoreSitesProvider) {
this.sitesProvider.createTableFromSchema(this.tableSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -15,7 +15,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreQuestionProvider } from '@core/question/providers/question'; import { CoreQuestionProvider } from '@core/question/providers/question';
@ -33,57 +33,61 @@ export class AddonModQuizOfflineProvider {
// Variables for database. // Variables for database.
static ATTEMPTS_TABLE = 'addon_mod_quiz_attempts'; static ATTEMPTS_TABLE = 'addon_mod_quiz_attempts';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'AddonModQuizOfflineProvider',
name: AddonModQuizOfflineProvider.ATTEMPTS_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'id', // Attempt ID. name: AddonModQuizOfflineProvider.ATTEMPTS_TABLE,
type: 'INTEGER', columns: [
primaryKey: true {
}, name: 'id', // Attempt ID.
{ type: 'INTEGER',
name: 'attempt', // Attempt number. primaryKey: true
type: 'INTEGER' },
}, {
{ name: 'attempt', // Attempt number.
name: 'courseid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'courseid',
name: 'userid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'userid',
name: 'quizid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'quizid',
name: 'currentpage', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'currentpage',
name: 'timecreated', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'timecreated',
name: 'timemodified', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'timemodified',
name: 'finished', type: 'INTEGER'
type: 'INTEGER' },
} {
] name: 'finished',
} type: 'INTEGER'
]; }
]
}
]
};
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private timeUtils: CoreTimeUtilsProvider, constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private timeUtils: CoreTimeUtilsProvider,
private questionProvider: CoreQuestionProvider, private translate: TranslateService, private utils: CoreUtilsProvider, private questionProvider: CoreQuestionProvider, private translate: TranslateService, private utils: CoreUtilsProvider,
private behaviourDelegate: CoreQuestionBehaviourDelegate) { private behaviourDelegate: CoreQuestionBehaviourDelegate) {
this.logger = logger.getInstance('AddonModQuizOfflineProvider'); this.logger = logger.getInstance('AddonModQuizOfflineProvider');
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreSyncProvider } from '@providers/sync'; import { CoreSyncProvider } from '@providers/sync';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
@ -34,95 +34,99 @@ export class AddonModScormOfflineProvider {
// Variables for database. // Variables for database.
static ATTEMPTS_TABLE = 'addon_mod_scorm_offline_attempts'; static ATTEMPTS_TABLE = 'addon_mod_scorm_offline_attempts';
static TRACKS_TABLE = 'addon_mod_scorm_offline_scos_tracks'; static TRACKS_TABLE = 'addon_mod_scorm_offline_scos_tracks';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'AddonModScormOfflineProvider',
name: AddonModScormOfflineProvider.ATTEMPTS_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'scormid', name: AddonModScormOfflineProvider.ATTEMPTS_TABLE,
type: 'INTEGER', columns: [
notNull: true {
}, name: 'scormid',
{ type: 'INTEGER',
name: 'attempt', // Attempt number. notNull: true
type: 'INTEGER', },
notNull: true {
}, name: 'attempt', // Attempt number.
{ type: 'INTEGER',
name: 'userid', notNull: true
type: 'INTEGER', },
notNull: true {
}, name: 'userid',
{ type: 'INTEGER',
name: 'courseid', notNull: true
type: 'INTEGER' },
}, {
{ name: 'courseid',
name: 'timecreated', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'timecreated',
name: 'timemodified', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'timemodified',
name: 'snapshot', type: 'INTEGER'
type: 'TEXT' },
}, {
], name: 'snapshot',
primaryKeys: ['scormid', 'userid', 'attempt'] type: 'TEXT'
}, },
{ ],
name: AddonModScormOfflineProvider.TRACKS_TABLE, primaryKeys: ['scormid', 'userid', 'attempt']
columns: [ },
{ {
name: 'scormid', name: AddonModScormOfflineProvider.TRACKS_TABLE,
type: 'INTEGER', columns: [
notNull: true {
}, name: 'scormid',
{ type: 'INTEGER',
name: 'attempt', // Attempt number. notNull: true
type: 'INTEGER', },
notNull: true {
}, name: 'attempt', // Attempt number.
{ type: 'INTEGER',
name: 'userid', notNull: true
type: 'INTEGER', },
notNull: true {
}, name: 'userid',
{ type: 'INTEGER',
name: 'scoid', notNull: true
type: 'INTEGER', },
notNull: true {
}, name: 'scoid',
{ type: 'INTEGER',
name: 'element', notNull: true
type: 'TEXT', },
notNull: true {
}, name: 'element',
{ type: 'TEXT',
name: 'value', notNull: true
type: 'TEXT' },
}, {
{ name: 'value',
name: 'timemodified', type: 'TEXT'
type: 'INTEGER' },
}, {
{ name: 'timemodified',
name: 'synced', type: 'INTEGER'
type: 'INTEGER' },
}, {
], name: 'synced',
primaryKeys: ['scormid', 'userid', 'attempt', 'scoid', 'element'] type: 'INTEGER'
} },
]; ],
primaryKeys: ['scormid', 'userid', 'attempt', 'scoid', 'element']
}
]
};
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private timeUtils: CoreTimeUtilsProvider, constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private timeUtils: CoreTimeUtilsProvider,
private syncProvider: CoreSyncProvider, private utils: CoreUtilsProvider, private textUtils: CoreTextUtilsProvider, private syncProvider: CoreSyncProvider, private utils: CoreUtilsProvider, private textUtils: CoreTextUtilsProvider,
private userProvider: CoreUserProvider) { private userProvider: CoreUserProvider) {
this.logger = logger.getInstance('AddonModScormOfflineProvider'); this.logger = logger.getInstance('AddonModScormOfflineProvider');
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
/** /**
@ -27,42 +27,46 @@ export class AddonModSurveyOfflineProvider {
// Variables for database. // Variables for database.
static SURVEY_TABLE = 'addon_mod_survey_answers'; static SURVEY_TABLE = 'addon_mod_survey_answers';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'AddonModSurveyOfflineProvider',
name: AddonModSurveyOfflineProvider.SURVEY_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'surveyid', name: AddonModSurveyOfflineProvider.SURVEY_TABLE,
type: 'INTEGER' columns: [
}, {
{ name: 'surveyid',
name: 'name', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'name',
name: 'courseid', type: 'TEXT'
type: 'INTEGER' },
}, {
{ name: 'courseid',
name: 'userid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'userid',
name: 'answers', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'answers',
name: 'timecreated', type: 'TEXT'
type: 'INTEGER' },
} {
], name: 'timecreated',
primaryKeys: ['surveyid', 'userid'] type: 'INTEGER'
} }
]; ],
primaryKeys: ['surveyid', 'userid']
}
]
};
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private textUtils: CoreTextUtilsProvider) { constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private textUtils: CoreTextUtilsProvider) {
this.logger = logger.getInstance('AddonModSurveyOfflineProvider'); this.logger = logger.getInstance('AddonModSurveyOfflineProvider');
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
/** /**
* Service to handle offline wiki. * Service to handle offline wiki.
@ -26,62 +26,66 @@ export class AddonModWikiOfflineProvider {
// Variables for database. // Variables for database.
static NEW_PAGES_TABLE = 'addon_mod_wiki_new_pages_store'; static NEW_PAGES_TABLE = 'addon_mod_wiki_new_pages_store';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'AddonModWikiOfflineProvider',
name: AddonModWikiOfflineProvider.NEW_PAGES_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'wikiid', name: AddonModWikiOfflineProvider.NEW_PAGES_TABLE,
type: 'INTEGER' columns: [
}, {
{ name: 'wikiid',
name: 'subwikiid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'subwikiid',
name: 'userid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'userid',
name: 'groupid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'groupid',
name: 'title', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'title',
name: 'cachedcontent', type: 'TEXT'
type: 'TEXT' },
}, {
{ name: 'cachedcontent',
name: 'contentformat', type: 'TEXT'
type: 'TEXT' },
}, {
{ name: 'contentformat',
name: 'courseid', type: 'TEXT'
type: 'INTEGER' },
}, {
{ name: 'courseid',
name: 'timecreated', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'timecreated',
name: 'timemodified', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'timemodified',
name: 'caneditpage', type: 'INTEGER'
type: 'INTEGER' },
} {
], name: 'caneditpage',
primaryKeys: ['wikiid', 'subwikiid', 'userid', 'groupid', 'title'] type: 'INTEGER'
} }
]; ],
primaryKeys: ['wikiid', 'subwikiid', 'userid', 'groupid', 'title']
}
]
};
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider) { constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider) {
this.logger = logger.getInstance('AddonModWikiOfflineProvider'); this.logger = logger.getInstance('AddonModWikiOfflineProvider');
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreFileProvider } from '@providers/file'; import { CoreFileProvider } from '@providers/file';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
@ -30,146 +30,150 @@ export class AddonModWorkshopOfflineProvider {
static EVALUATE_SUBMISSIONS_TABLE = 'addon_mod_workshop_evaluate_submissions'; static EVALUATE_SUBMISSIONS_TABLE = 'addon_mod_workshop_evaluate_submissions';
static EVALUATE_ASSESSMENTS_TABLE = 'addon_mod_workshop_evaluate_assessments'; static EVALUATE_ASSESSMENTS_TABLE = 'addon_mod_workshop_evaluate_assessments';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'AddonModWorkshopOfflineProvider',
name: AddonModWorkshopOfflineProvider.SUBMISSIONS_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'workshopid', name: AddonModWorkshopOfflineProvider.SUBMISSIONS_TABLE,
type: 'INTEGER', columns: [
}, {
{ name: 'workshopid',
name: 'submissionid', type: 'INTEGER',
type: 'INTEGER', },
}, {
{ name: 'submissionid',
name: 'action', type: 'INTEGER',
type: 'TEXT', },
}, {
{ name: 'action',
name: 'courseid', type: 'TEXT',
type: 'INTEGER', },
}, {
{ name: 'courseid',
name: 'title', type: 'INTEGER',
type: 'TEXT', },
}, {
{ name: 'title',
name: 'content', type: 'TEXT',
type: 'TEXT', },
}, {
{ name: 'content',
name: 'attachmentsid', type: 'TEXT',
type: 'TEXT', },
}, {
{ name: 'attachmentsid',
name: 'timemodified', type: 'TEXT',
type: 'INTEGER', },
} {
], name: 'timemodified',
primaryKeys: ['workshopid', 'submissionid', 'action'] type: 'INTEGER',
}, }
{ ],
name: AddonModWorkshopOfflineProvider.ASSESSMENTS_TABLE, primaryKeys: ['workshopid', 'submissionid', 'action']
columns: [ },
{ {
name: 'workshopid', name: AddonModWorkshopOfflineProvider.ASSESSMENTS_TABLE,
type: 'INTEGER', columns: [
}, {
{ name: 'workshopid',
name: 'assessmentid', type: 'INTEGER',
type: 'INTEGER', },
}, {
{ name: 'assessmentid',
name: 'courseid', type: 'INTEGER',
type: 'INTEGER', },
}, {
{ name: 'courseid',
name: 'inputdata', type: 'INTEGER',
type: 'TEXT', },
}, {
{ name: 'inputdata',
name: 'timemodified', type: 'TEXT',
type: 'INTEGER', },
}, {
], name: 'timemodified',
primaryKeys: ['workshopid', 'assessmentid'] type: 'INTEGER',
}, },
{ ],
name: AddonModWorkshopOfflineProvider.EVALUATE_SUBMISSIONS_TABLE, primaryKeys: ['workshopid', 'assessmentid']
columns: [ },
{ {
name: 'workshopid', name: AddonModWorkshopOfflineProvider.EVALUATE_SUBMISSIONS_TABLE,
type: 'INTEGER', columns: [
}, {
{ name: 'workshopid',
name: 'submissionid', type: 'INTEGER',
type: 'INTEGER', },
}, {
{ name: 'submissionid',
name: 'courseid', type: 'INTEGER',
type: 'INTEGER', },
}, {
{ name: 'courseid',
name: 'timemodified', type: 'INTEGER',
type: 'INTEGER', },
}, {
{ name: 'timemodified',
name: 'feedbacktext', type: 'INTEGER',
type: 'TEXT', },
}, {
{ name: 'feedbacktext',
name: 'published', type: 'TEXT',
type: 'INTEGER', },
}, {
{ name: 'published',
name: 'gradeover', type: 'INTEGER',
type: 'TEXT', },
}, {
], name: 'gradeover',
primaryKeys: ['workshopid', 'submissionid'] type: 'TEXT',
}, },
{ ],
name: AddonModWorkshopOfflineProvider.EVALUATE_ASSESSMENTS_TABLE, primaryKeys: ['workshopid', 'submissionid']
columns: [ },
{ {
name: 'workshopid', name: AddonModWorkshopOfflineProvider.EVALUATE_ASSESSMENTS_TABLE,
type: 'INTEGER', columns: [
}, {
{ name: 'workshopid',
name: 'assessmentid', type: 'INTEGER',
type: 'INTEGER', },
}, {
{ name: 'assessmentid',
name: 'courseid', type: 'INTEGER',
type: 'INTEGER', },
}, {
{ name: 'courseid',
name: 'timemodified', type: 'INTEGER',
type: 'INTEGER', },
}, {
{ name: 'timemodified',
name: 'feedbacktext', type: 'INTEGER',
type: 'TEXT', },
}, {
{ name: 'feedbacktext',
name: 'weight', type: 'TEXT',
type: 'INTEGER', },
}, {
{ name: 'weight',
name: 'gradinggradeover', type: 'INTEGER',
type: 'TEXT', },
}, {
], name: 'gradinggradeover',
primaryKeys: ['workshopid', 'assessmentid'] type: 'TEXT',
} },
]; ],
primaryKeys: ['workshopid', 'assessmentid']
}
]
};
constructor(private fileProvider: CoreFileProvider, constructor(private fileProvider: CoreFileProvider,
private sitesProvider: CoreSitesProvider, private sitesProvider: CoreSitesProvider,
private textUtils: CoreTextUtilsProvider, private textUtils: CoreTextUtilsProvider,
private timeUtils: CoreTimeUtilsProvider) { private timeUtils: CoreTimeUtilsProvider) {
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
/** /**
@ -26,46 +26,50 @@ export class AddonNotesOfflineProvider {
// Variables for database. // Variables for database.
static NOTES_TABLE = 'addon_notes_offline_notes'; static NOTES_TABLE = 'addon_notes_offline_notes';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'AddonNotesOfflineProvider',
name: AddonNotesOfflineProvider.NOTES_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'userid', name: AddonNotesOfflineProvider.NOTES_TABLE,
type: 'INTEGER' columns: [
}, {
{ name: 'userid',
name: 'courseid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'courseid',
name: 'publishstate', type: 'INTEGER'
type: 'TEXT', },
}, {
{ name: 'publishstate',
name: 'content', type: 'TEXT',
type: 'TEXT' },
}, {
{ name: 'content',
name: 'format', type: 'TEXT'
type: 'INTEGER' },
}, {
{ name: 'format',
name: 'created', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'created',
name: 'lastmodified', type: 'INTEGER'
type: 'INTEGER' },
} {
], name: 'lastmodified',
primaryKeys: ['userid', 'content', 'created'] type: 'INTEGER'
} }
]; ],
primaryKeys: ['userid', 'content', 'created']
}
]
};
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private timeUtils: CoreTimeUtilsProvider) { constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private timeUtils: CoreTimeUtilsProvider) {
this.logger = logger.getInstance('AddonNotesOfflineProvider'); this.logger = logger.getInstance('AddonNotesOfflineProvider');
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -28,6 +28,7 @@ import { CoreConfigProvider } from '@providers/config';
import { CoreConstants } from '@core/constants'; import { CoreConstants } from '@core/constants';
import { CoreConfigConstants } from '../../../configconstants'; import { CoreConfigConstants } from '../../../configconstants';
import { ILocalNotification } from '@ionic-native/local-notifications'; import { ILocalNotification } from '@ionic-native/local-notifications';
import { SQLiteDBTableSchema } from '@classes/sqlitedb';
/** /**
* Service to handle push notifications. * Service to handle push notifications.
@ -41,7 +42,7 @@ export class AddonPushNotificationsProvider {
// Variables for database. // Variables for database.
static BADGE_TABLE = 'addon_pushnotifications_badge'; static BADGE_TABLE = 'addon_pushnotifications_badge';
protected tablesSchema = [ protected tablesSchema: SQLiteDBTableSchema[] = [
{ {
name: AddonPushNotificationsProvider.BADGE_TABLE, name: AddonPushNotificationsProvider.BADGE_TABLE,
columns: [ columns: [

View File

@ -166,47 +166,8 @@ export class CoreSite {
protected wsProvider: CoreWSProvider; protected wsProvider: CoreWSProvider;
// Variables for the database. // Variables for the database.
protected WS_CACHE_TABLE = 'wscache'; static WS_CACHE_TABLE = 'wscache';
protected CONFIG_TABLE = 'core_site_config'; static CONFIG_TABLE = 'core_site_config';
protected tableSchemas = [
{
name: this.WS_CACHE_TABLE,
columns: [
{
name: 'id',
type: 'TEXT',
primaryKey: true
},
{
name: 'data',
type: 'TEXT'
},
{
name: 'key',
type: 'TEXT'
},
{
name: 'expirationTime',
type: 'INTEGER'
}
]
},
{
name: this.CONFIG_TABLE,
columns: [
{
name: 'name',
type: 'TEXT',
unique: true,
notNull: true
},
{
name: 'value'
}
]
}
];
// Versions of Moodle releases. // Versions of Moodle releases.
protected MOODLE_RELEASES = { protected MOODLE_RELEASES = {
@ -267,7 +228,6 @@ export class CoreSite {
*/ */
initDB(): void { initDB(): void {
this.db = this.dbProvider.getDB('Site-' + this.id); this.db = this.dbProvider.getDB('Site-' + this.id);
this.db.createTablesFromSchema(this.tableSchemas);
} }
/** /**
@ -784,10 +744,10 @@ export class CoreSite {
let promise; let promise;
if (preSets.getCacheUsingCacheKey || (emergency && preSets.getEmergencyCacheUsingCacheKey)) { if (preSets.getCacheUsingCacheKey || (emergency && preSets.getEmergencyCacheUsingCacheKey)) {
promise = this.db.getRecords(this.WS_CACHE_TABLE, { key: preSets.cacheKey }).then((entries) => { promise = this.db.getRecords(CoreSite.WS_CACHE_TABLE, { key: preSets.cacheKey }).then((entries) => {
if (!entries.length) { if (!entries.length) {
// Cache key not found, get by params sent. // Cache key not found, get by params sent.
return this.db.getRecord(this.WS_CACHE_TABLE, { id: id }); return this.db.getRecord(CoreSite.WS_CACHE_TABLE, { id: id });
} else if (entries.length > 1) { } else if (entries.length > 1) {
// More than one entry found. Search the one with same ID as this call. // More than one entry found. Search the one with same ID as this call.
for (let i = 0, len = entries.length; i < len; i++) { for (let i = 0, len = entries.length; i < len; i++) {
@ -801,13 +761,13 @@ export class CoreSite {
return entries[0]; return entries[0];
}); });
} else { } else {
promise = this.db.getRecord(this.WS_CACHE_TABLE, { id: id }).catch(() => { promise = this.db.getRecord(CoreSite.WS_CACHE_TABLE, { id: id }).catch(() => {
// Entry not found, try to get it using the old ID. // Entry not found, try to get it using the old ID.
const oldId = this.getCacheOldId(method, originalData || {}); const oldId = this.getCacheOldId(method, originalData || {});
return this.db.getRecord(this.WS_CACHE_TABLE, { id: oldId }).then((entry) => { return this.db.getRecord(CoreSite.WS_CACHE_TABLE, { id: oldId }).then((entry) => {
// Update the entry ID to use the new one. // Update the entry ID to use the new one.
this.db.updateRecords(this.WS_CACHE_TABLE, {id: id}, {id: oldId}); this.db.updateRecords(CoreSite.WS_CACHE_TABLE, {id: id}, {id: oldId});
return entry; return entry;
}); });
@ -877,7 +837,7 @@ export class CoreSite {
entry.key = preSets.cacheKey; entry.key = preSets.cacheKey;
} }
return this.db.insertRecord(this.WS_CACHE_TABLE, entry); return this.db.insertRecord(CoreSite.WS_CACHE_TABLE, entry);
}); });
} }
@ -898,10 +858,10 @@ export class CoreSite {
const id = this.getCacheId(method, data); const id = this.getCacheId(method, data);
if (allCacheKey) { if (allCacheKey) {
return this.db.deleteRecords(this.WS_CACHE_TABLE, { key: preSets.cacheKey }); return this.db.deleteRecords(CoreSite.WS_CACHE_TABLE, { key: preSets.cacheKey });
} }
return this.db.deleteRecords(this.WS_CACHE_TABLE, { id: id }); return this.db.deleteRecords(CoreSite.WS_CACHE_TABLE, { id: id });
} }
/* /*
@ -935,7 +895,7 @@ export class CoreSite {
this.logger.debug('Invalidate all the cache for site: ' + this.id); this.logger.debug('Invalidate all the cache for site: ' + this.id);
return this.db.updateRecords(this.WS_CACHE_TABLE, { expirationTime: 0 }); return this.db.updateRecords(CoreSite.WS_CACHE_TABLE, { expirationTime: 0 });
} }
/** /**
@ -954,7 +914,7 @@ export class CoreSite {
this.logger.debug('Invalidate cache for key: ' + key); this.logger.debug('Invalidate cache for key: ' + key);
return this.db.updateRecords(this.WS_CACHE_TABLE, { expirationTime: 0 }, { key: key }); return this.db.updateRecords(CoreSite.WS_CACHE_TABLE, { expirationTime: 0 }, { key: key });
} }
/** /**
@ -997,7 +957,7 @@ export class CoreSite {
this.logger.debug('Invalidate cache for key starting with: ' + key); this.logger.debug('Invalidate cache for key starting with: ' + key);
const sql = 'UPDATE ' + this.WS_CACHE_TABLE + ' SET expirationTime=0 WHERE key LIKE ?'; const sql = 'UPDATE ' + CoreSite.WS_CACHE_TABLE + ' SET expirationTime=0 WHERE key LIKE ?';
return this.db.execute(sql, [key + '%']); return this.db.execute(sql, [key + '%']);
} }
@ -1590,7 +1550,7 @@ export class CoreSite {
* @return {Promise<any>} Promise resolved when done. * @return {Promise<any>} Promise resolved when done.
*/ */
deleteSiteConfig(name: string): Promise<any> { deleteSiteConfig(name: string): Promise<any> {
return this.db.deleteRecords(this.CONFIG_TABLE, { name: name }); return this.db.deleteRecords(CoreSite.CONFIG_TABLE, { name: name });
} }
/** /**
@ -1601,7 +1561,7 @@ export class CoreSite {
* @return {Promise<any>} Resolves upon success along with the config data. Reject on failure. * @return {Promise<any>} Resolves upon success along with the config data. Reject on failure.
*/ */
getLocalSiteConfig(name: string, defaultValue?: any): Promise<any> { getLocalSiteConfig(name: string, defaultValue?: any): Promise<any> {
return this.db.getRecord(this.CONFIG_TABLE, { name: name }).then((entry) => { return this.db.getRecord(CoreSite.CONFIG_TABLE, { name: name }).then((entry) => {
return entry.value; return entry.value;
}).catch((error) => { }).catch((error) => {
if (typeof defaultValue != 'undefined') { if (typeof defaultValue != 'undefined') {
@ -1620,6 +1580,6 @@ export class CoreSite {
* @return {Promise<any>} Promise resolved when done. * @return {Promise<any>} Promise resolved when done.
*/ */
setLocalSiteConfig(name: string, value: number | string): Promise<any> { setLocalSiteConfig(name: string, value: number | string): Promise<any> {
return this.db.insertRecord(this.CONFIG_TABLE, { name: name, value: value }); return this.db.insertRecord(CoreSite.CONFIG_TABLE, { name: name, value: value });
} }
} }

View File

@ -15,6 +15,129 @@
import { SQLite, SQLiteObject } from '@ionic-native/sqlite'; import { SQLite, SQLiteObject } from '@ionic-native/sqlite';
import { Platform } from 'ionic-angular'; import { Platform } from 'ionic-angular';
/**
* Schema of a table.
*/
export interface SQLiteDBTableSchema {
/**
* The table name.
* @type {string}
*/
name: string;
/**
* The columns to create in the table.
* @type {SQLiteDBColumnSchema[]}
*/
columns: SQLiteDBColumnSchema[];
/**
* Names of columns that are primary key. Use it for compound primary keys.
* @type {string[]}
*/
primaryKeys?: string[];
/**
* List of sets of unique columns. E.g: [['section', 'title'], ['author', 'title']].
* @type {string[][]}
*/
uniqueKeys?: string[][];
/**
* List of foreign keys.
* @type {SQLiteDBForeignKeySchema[]}
*/
foreignKeys?: SQLiteDBForeignKeySchema[];
/**
* Check constraint for the table.
* @type {string}
*/
tableCheck?: string;
}
/**
* Schema of a column.
*/
export interface SQLiteDBColumnSchema {
/**
* Column's name.
* @type {string}
*/
name: string;
/**
* Column's type.
* @type {string}
*/
type?: 'INTEGER' | 'REAL' | 'TEXT' | 'BLOB';
/**
* Whether the column is a primary key. Use it only if primary key is a single column.
* @type {boolean}
*/
primaryKey?: boolean;
/**
* Whether it should be autoincremented. Only if primaryKey is true.
* @type {boolean}
*/
autoIncrement?: boolean;
/**
* True if column shouldn't be null.
* @type {boolean}
*/
notNull?: boolean;
/**
* WWhether the column is unique.
* @type {boolean}
*/
unique?: boolean;
/**
* Check constraint for the column.
* @type {string}
*/
check?: string;
/**
* Default value for the column.
* @type {string}
*/
default?: string;
}
/**
* Schema of a foreign key.
*/
export interface SQLiteDBForeignKeySchema {
/**
* Columns to include in this foreign key.
* @type {string[]}
*/
columns: string[];
/**
* The external table referenced by this key.
* @type {string}
*/
table: string;
/**
* List of referenced columns from the referenced table.
* @type {string[]}
*/
foreignColumns?: string[];
/**
* Text with the actions to apply to the foreign key.
* @type {string}
*/
actions?: string;
}
/** /**
* Class to interact with the local database. * Class to interact with the local database.
* *
@ -43,27 +166,15 @@ export class SQLiteDB {
* Helper function to create a table if it doesn't exist. * Helper function to create a table if it doesn't exist.
* *
* @param {string} name The table name. * @param {string} name The table name.
* @param {any[]} columns The columns to create in the table. Each column can have: * @param {SQLiteDBColumnSchema[]} columns The columns to create in the table.
* * {string} name Column's name.
* * {string} [type] Column's type.
* * {boolean} [primaryKey] If column is primary key. Use it only if primary key is a single column.
* * {boolean} [autoIncrement] Whether it should be autoincremented. Only if primaryKey is true.
* * {boolean} [notNull] True if column shouldn't be null.
* * {boolean} [unique] Whether the column is unique.
* * {string} [check] Check constraint for the column.
* * {string} [default] Default value for the column.
* @param {string[]} [primaryKeys] Names of columns that are primary key. Use it for compound primary keys. * @param {string[]} [primaryKeys] Names of columns that are primary key. Use it for compound primary keys.
* @param {string[][]} [uniqueKeys] List of sets of unique columns. E.g: [['section', 'title'], ['author', 'title']]. * @param {string[][]} [uniqueKeys] List of sets of unique columns. E.g: [['section', 'title'], ['author', 'title']].
* @param {any[]} [foreignKeys] List of foreign keys. Each key can have: * @param {SQLiteDBForeignKeySchema[]} [foreignKeys] List of foreign keys.
* * {string[]} columns Columns to include in this foreign key.
* * {string} table The external table referenced by this key.
* * {string[]} [foreignColumns] List of referenced columns from the referenced table.
* * {string} [actions] Text with the actions to apply to the foreign key.
* @param {string} [tableCheck] Check constraint for the table. * @param {string} [tableCheck] Check constraint for the table.
* @return SQL query. * @return SQL query.
*/ */
buildCreateTableSql(name: string, columns: any[], primaryKeys?: string[], uniqueKeys?: string[][], foreignKeys?: any[], buildCreateTableSql(name: string, columns: SQLiteDBColumnSchema[], primaryKeys?: string[], uniqueKeys?: string[][],
tableCheck?: string): string { foreignKeys?: SQLiteDBForeignKeySchema[], tableCheck?: string): string {
const columnsSql = []; const columnsSql = [];
let sql = `CREATE TABLE IF NOT EXISTS ${name} (`; let sql = `CREATE TABLE IF NOT EXISTS ${name} (`;
@ -207,27 +318,15 @@ export class SQLiteDB {
* Create a table if it doesn't exist. * Create a table if it doesn't exist.
* *
* @param {string} name The table name. * @param {string} name The table name.
* @param {any[]} columns The columns to create in the table. Each column can have: * @param {SQLiteDBColumnSchema[]} columns The columns to create in the table.
* * {string} name Column's name.
* * {string} [type] Column's type.
* * {boolean} [primaryKey] If column is primary key. Use it only if primary key is a single column.
* * {boolean} [autoIncrement] Whether it should be autoincremented. Only if primaryKey is true.
* * {boolean} [notNull] True if column shouldn't be null.
* * {boolean} [unique] Whether the column is unique.
* * {string} [check] Check constraint for the column.
* * {string} [default] Default value for the column.
* @param {string[]} [primaryKeys] Names of columns that are primary key. Use it for compound primary keys. * @param {string[]} [primaryKeys] Names of columns that are primary key. Use it for compound primary keys.
* @param {string[][]} [uniqueKeys] List of sets of unique columns. E.g: [['section', 'title'], ['author', 'title']]. * @param {string[][]} [uniqueKeys] List of sets of unique columns. E.g: [['section', 'title'], ['author', 'title']].
* @param {any[]} [foreignKeys] List of foreign keys. Each key can have: * @param {SQLiteDBForeignKeySchema[]} [foreignKeys] List of foreign keys.
* * {string[]} columns Columns to include in this foreign key.
* * {string} table The external table referenced by this key.
* * {string[]} [foreignColumns] List of referenced columns from the referenced table.
* * {string} [actions] Text with the actions to apply to the foreign key.
* @param {string} [tableCheck] Check constraint for the table. * @param {string} [tableCheck] Check constraint for the table.
* @return {Promise<any>} Promise resolved when success. * @return {Promise<any>} Promise resolved when success.
*/ */
createTable(name: string, columns: any[], primaryKeys?: string[], uniqueKeys?: string[][], foreignKeys?: any[], createTable(name: string, columns: SQLiteDBColumnSchema[], primaryKeys?: string[], uniqueKeys?: string[][],
tableCheck?: string): Promise<any> { foreignKeys?: SQLiteDBForeignKeySchema[], tableCheck?: string): Promise<any> {
const sql = this.buildCreateTableSql(name, columns, primaryKeys, uniqueKeys, foreignKeys, tableCheck); const sql = this.buildCreateTableSql(name, columns, primaryKeys, uniqueKeys, foreignKeys, tableCheck);
return this.execute(sql); return this.execute(sql);
@ -236,10 +335,10 @@ export class SQLiteDB {
/** /**
* Create a table if it doesn't exist from a schema. * Create a table if it doesn't exist from a schema.
* *
* @param {any} table Table schema. * @param {SQLiteDBTableSchema} table Table schema.
* @return {Promise<any>} Promise resolved when success. * @return {Promise<any>} Promise resolved when success.
*/ */
createTableFromSchema(table: any): Promise<any> { createTableFromSchema(table: SQLiteDBTableSchema): Promise<any> {
return this.createTable(table.name, table.columns, table.primaryKeys, table.uniqueKeys, return this.createTable(table.name, table.columns, table.primaryKeys, table.uniqueKeys,
table.foreignKeys, table.tableCheck); table.foreignKeys, table.tableCheck);
} }
@ -247,10 +346,10 @@ export class SQLiteDB {
/** /**
* Create several tables if they don't exist from a list of schemas. * Create several tables if they don't exist from a list of schemas.
* *
* @param {any[]} tables List of table schema. * @param {SQLiteDBTableSchema[]} tables List of table schema.
* @return {Promise<any>} Promise resolved when success. * @return {Promise<any>} Promise resolved when success.
*/ */
createTablesFromSchema(tables: any[]): Promise<any> { createTablesFromSchema(tables: SQLiteDBTableSchema[]): Promise<any> {
const promises = []; const promises = [];
tables.forEach((table) => { tables.forEach((table) => {
promises.push(this.createTableFromSchema(table)); promises.push(this.createTableFromSchema(table));
@ -308,6 +407,16 @@ export class SQLiteDB {
return this.execute(`DELETE FROM ${table} ${select}`, params); return this.execute(`DELETE FROM ${table} ${select}`, params);
} }
/**
* Drop a table if it exists.
*
* @param {string} name The table name.
* @return {Promise<any>} Promise resolved when success.
*/
dropTable(name: string): Promise<any> {
return this.execute(`DROP TABLE IF EXISTS ${name}`);
}
/** /**
* Execute a SQL query. * Execute a SQL query.
* IMPORTANT: Use this function only if you cannot use any of the other functions in this API. Please take into account that * IMPORTANT: Use this function only if you cannot use any of the other functions in this API. Please take into account that
@ -684,6 +793,23 @@ export class SQLiteDB {
return this.executeBatch(statements); return this.executeBatch(statements);
} }
/**
* Insert multiple records into database from another table.
*
* @param {string} table The database table to be inserted into.
* @param {string} source The database table to get the records from.
* @param {object} [conditions] The conditions to build the where clause. Must not contain numeric indexes.
* @param {string} [fields='*'] A comma separated list of fields to return.
* @return {Promise<any>} Promise resolved when done.
*/
insertRecordsFrom(table: string, source: string, conditions?: object, fields: string = '*'): Promise<any> {
const selectAndParams = this.whereClause(conditions);
const select = selectAndParams[0] ? 'WHERE ' + selectAndParams[0] : '';
const params = selectAndParams[1];
return this.execute(`INSERT INTO ${table} SELECT ${fields} FROM ${source} ${select}`, params);
}
/** /**
* Ensures that limit params are numeric and positive integers, to be passed to the database. * Ensures that limit params are numeric and positive integers, to be passed to the database.
* We explicitly treat null, '' and -1 as 0 in order to provide compatibility with how limit * We explicitly treat null, '' and -1 as 0 in order to provide compatibility with how limit
@ -776,6 +902,16 @@ export class SQLiteDB {
}); });
} }
/**
* Test whether a table exists..
*
* @param {string} name The table name.
* @return {Promise<void>} Promise resolved if exists, rejected otherwise.
*/
tableExists(name: string): Promise<void> {
return this.recordExists('sqlite_master', {type: 'table', tbl_name: name});
}
/** /**
* Update one or more records in a table. * Update one or more records in a table.
* *

View File

@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
/** /**
* Service to handle offline data for courses. * Service to handle offline data for courses.
@ -23,37 +23,41 @@ export class CoreCourseOfflineProvider {
// Variables for database. // Variables for database.
static MANUAL_COMPLETION_TABLE = 'course_manual_completion'; static MANUAL_COMPLETION_TABLE = 'course_manual_completion';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'CoreCourseOfflineProvider',
name: CoreCourseOfflineProvider.MANUAL_COMPLETION_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'cmid', name: CoreCourseOfflineProvider.MANUAL_COMPLETION_TABLE,
type: 'INTEGER', columns: [
primaryKey: true {
}, name: 'cmid',
{ type: 'INTEGER',
name: 'completed', primaryKey: true
type: 'INTEGER' },
}, {
{ name: 'completed',
name: 'courseid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'courseid',
name: 'coursename', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'coursename',
name: 'timecompleted', type: 'TEXT'
type: 'INTEGER' },
} {
] name: 'timecompleted',
} type: 'INTEGER'
]; }
]
}
]
};
constructor(private sitesProvider: CoreSitesProvider) { constructor(private sitesProvider: CoreSitesProvider) {
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -17,7 +17,7 @@ import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app'; import { CoreAppProvider } from '@providers/app';
import { CoreEventsProvider } from '@providers/events'; import { CoreEventsProvider } from '@providers/events';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreSiteWSPreSets, CoreSite } from '@classes/site'; import { CoreSiteWSPreSets, CoreSite } from '@classes/site';
@ -47,34 +47,40 @@ export class CoreCourseProvider {
// Variables for database. // Variables for database.
protected COURSE_STATUS_TABLE = 'course_status'; protected COURSE_STATUS_TABLE = 'course_status';
protected courseStatusTableSchema = { protected siteSchema: CoreSiteSchema = {
name: this.COURSE_STATUS_TABLE, name: 'CoreCourseProvider',
columns: [ version: 1,
tables: [
{ {
name: 'id', name: this.COURSE_STATUS_TABLE,
type: 'INTEGER', columns: [
primaryKey: true {
}, name: 'id',
{ type: 'INTEGER',
name: 'status', primaryKey: true
type: 'TEXT', },
notNull: true {
}, name: 'status',
{ type: 'TEXT',
name: 'previous', notNull: true
type: 'TEXT' },
}, {
{ name: 'previous',
name: 'updated', type: 'TEXT'
type: 'INTEGER' },
}, {
{ name: 'updated',
name: 'downloadTime', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'downloadTime',
name: 'previousDownloadTime', type: 'INTEGER'
type: 'INTEGER' },
{
name: 'previousDownloadTime',
type: 'INTEGER'
}
]
} }
] ]
}; };
@ -91,7 +97,7 @@ export class CoreCourseProvider {
private courseOffline: CoreCourseOfflineProvider, private appProvider: CoreAppProvider) { private courseOffline: CoreCourseOfflineProvider, private appProvider: CoreAppProvider) {
this.logger = logger.getInstance('CoreCourseProvider'); this.logger = logger.getInstance('CoreCourseProvider');
this.sitesProvider.createTableFromSchema(this.courseStatusTableSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -17,7 +17,7 @@ import { CoreEventsProvider } from '@providers/events';
import { CoreFileProvider } from '@providers/file'; import { CoreFileProvider } from '@providers/file';
import { CoreFilepoolProvider } from '@providers/filepool'; import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from './course'; import { CoreCourseProvider } from './course';
@ -202,18 +202,24 @@ export interface CoreCourseModulePrefetchHandler extends CoreDelegateHandler {
export class CoreCourseModulePrefetchDelegate extends CoreDelegate { export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
// Variables for database. // Variables for database.
protected CHECK_UPDATES_TIMES_TABLE = 'check_updates_times'; protected CHECK_UPDATES_TIMES_TABLE = 'check_updates_times';
protected checkUpdatesTableSchema = { protected siteSchema: CoreSiteSchema = {
name: this.CHECK_UPDATES_TIMES_TABLE, name: 'CoreCourseModulePrefetchDelegate',
columns: [ version: 1,
tables: [
{ {
name: 'courseId', name: this.CHECK_UPDATES_TIMES_TABLE,
type: 'INTEGER', columns: [
primaryKey: true {
}, name: 'courseId',
{ type: 'INTEGER',
name: 'time', primaryKey: true
type: 'INTEGER', },
notNull: true {
name: 'time',
type: 'INTEGER',
notNull: true
}
]
} }
] ]
}; };
@ -242,7 +248,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
protected eventsProvider: CoreEventsProvider) { protected eventsProvider: CoreEventsProvider) {
super('CoreCourseModulePrefetchDelegate', loggerProvider, sitesProvider, eventsProvider); super('CoreCourseModulePrefetchDelegate', loggerProvider, sitesProvider, eventsProvider);
this.sitesProvider.createTableFromSchema(this.checkUpdatesTableSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
eventsProvider.on(CoreEventsProvider.LOGOUT, this.clearStatusCache.bind(this)); eventsProvider.on(CoreEventsProvider.LOGOUT, this.clearStatusCache.bind(this));
eventsProvider.on(CoreEventsProvider.PACKAGE_STATUS_CHANGED, (data) => { eventsProvider.on(CoreEventsProvider.PACKAGE_STATUS_CHANGED, (data) => {

View File

@ -20,7 +20,7 @@ import { LocalNotifications, ILocalNotification } from '@ionic-native/local-noti
import { CoreAppProvider } from '@providers/app'; import { CoreAppProvider } from '@providers/app';
import { CoreInitDelegate, CoreInitHandler } from '@providers/init'; import { CoreInitDelegate, CoreInitHandler } from '@providers/init';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreLocalNotificationsProvider } from '@providers/local-notifications'; import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { FileTransferErrorMock } from './file-transfer'; import { FileTransferErrorMock } from './file-transfer';
@ -40,33 +40,37 @@ export class CoreEmulatorHelperProvider implements CoreInitHandler {
// Variables for database. // Variables for database.
protected LAST_RECEIVED_NOTIFICATION_TABLE = 'core_emulator_last_received_notification'; protected LAST_RECEIVED_NOTIFICATION_TABLE = 'core_emulator_last_received_notification';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'CoreEmulatorHelperProvider',
name: this.LAST_RECEIVED_NOTIFICATION_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'component', name: this.LAST_RECEIVED_NOTIFICATION_TABLE,
type: 'TEXT' columns: [
}, {
{ name: 'component',
name: 'id', type: 'TEXT'
type: 'INTEGER', },
}, {
{ name: 'id',
name: 'timecreated', type: 'INTEGER',
type: 'INTEGER', },
}, {
], name: 'timecreated',
primaryKeys: ['component'] type: 'INTEGER',
} },
]; ],
primaryKeys: ['component']
}
]
};
constructor(private file: File, private fileProvider: CoreFileProvider, private utils: CoreUtilsProvider, constructor(private file: File, private fileProvider: CoreFileProvider, private utils: CoreUtilsProvider,
logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private localNotif: LocalNotifications, logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private localNotif: LocalNotifications,
private captureHelper: CoreEmulatorCaptureHelperProvider, private timeUtils: CoreTimeUtilsProvider, private captureHelper: CoreEmulatorCaptureHelperProvider, private timeUtils: CoreTimeUtilsProvider,
private appProvider: CoreAppProvider, private localNotifProvider: CoreLocalNotificationsProvider) { private appProvider: CoreAppProvider, private localNotifProvider: CoreLocalNotificationsProvider) {
this.logger = logger.getInstance('CoreEmulatorHelper'); this.logger = logger.getInstance('CoreEmulatorHelper');
sitesProvider.createTablesFromSchema(this.tablesSchema); sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -17,7 +17,7 @@ import { LocalNotifications, ILocalNotification, ILocalNotificationAction } from
import { CoreAppProvider } from '@providers/app'; import { CoreAppProvider } from '@providers/app';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
import { SQLiteDB } from '@classes/sqlitedb'; import { SQLiteDB, SQLiteDBTableSchema } from '@classes/sqlitedb';
import { CoreConstants } from '@core/constants'; import { CoreConstants } from '@core/constants';
import { CoreConfigConstants } from '../../../configconstants'; import { CoreConfigConstants } from '../../../configconstants';
import * as moment from 'moment'; import * as moment from 'moment';
@ -43,7 +43,7 @@ export class LocalNotificationsMock extends LocalNotifications {
// Variables for database. // Variables for database.
protected DESKTOP_NOTIFS_TABLE = 'desktop_local_notifications'; protected DESKTOP_NOTIFS_TABLE = 'desktop_local_notifications';
protected tableSchema = { protected tableSchema: SQLiteDBTableSchema = {
name: this.DESKTOP_NOTIFS_TABLE, name: this.DESKTOP_NOTIFS_TABLE,
columns: [ columns: [
{ {

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
@ -63,86 +63,90 @@ export class CoreQuestionProvider {
// Variables for database. // Variables for database.
protected QUESTION_TABLE = 'questions'; protected QUESTION_TABLE = 'questions';
protected QUESTION_ANSWERS_TABLE = 'question_answers'; protected QUESTION_ANSWERS_TABLE = 'question_answers';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'CoreQuestionProvider',
name: this.QUESTION_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'component', name: this.QUESTION_TABLE,
type: 'TEXT', columns: [
notNull: true {
}, name: 'component',
{ type: 'TEXT',
name: 'attemptid', notNull: true
type: 'INTEGER', },
notNull: true {
}, name: 'attemptid',
{ type: 'INTEGER',
name: 'slot', notNull: true
type: 'INTEGER', },
notNull: true {
}, name: 'slot',
{ type: 'INTEGER',
name: 'componentid', notNull: true
type: 'INTEGER' },
}, {
{ name: 'componentid',
name: 'userid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'userid',
name: 'number', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'number',
name: 'state', type: 'INTEGER'
type: 'TEXT' },
} {
], name: 'state',
primaryKeys: ['component', 'attemptid', 'slot'] type: 'TEXT'
}, }
{ ],
name: this.QUESTION_ANSWERS_TABLE, primaryKeys: ['component', 'attemptid', 'slot']
columns: [ },
{ {
name: 'component', name: this.QUESTION_ANSWERS_TABLE,
type: 'TEXT', columns: [
notNull: true {
}, name: 'component',
{ type: 'TEXT',
name: 'attemptid', notNull: true
type: 'INTEGER', },
notNull: true {
}, name: 'attemptid',
{ type: 'INTEGER',
name: 'name', notNull: true
type: 'TEXT', },
notNull: true {
}, name: 'name',
{ type: 'TEXT',
name: 'componentid', notNull: true
type: 'INTEGER' },
}, {
{ name: 'componentid',
name: 'userid', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'userid',
name: 'questionslot', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'questionslot',
name: 'value', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'value',
name: 'timemodified', type: 'TEXT'
type: 'INTEGER' },
} {
], name: 'timemodified',
primaryKeys: ['component', 'attemptid', 'name'] type: 'INTEGER'
} }
]; ],
primaryKeys: ['component', 'attemptid', 'name']
}
]
};
protected QUESTION_PREFIX_REGEX = /q\d+:(\d+)_/; protected QUESTION_PREFIX_REGEX = /q\d+:(\d+)_/;
protected STATES: {[name: string]: CoreQuestionState} = { protected STATES: {[name: string]: CoreQuestionState} = {
@ -244,7 +248,7 @@ export class CoreQuestionProvider {
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private timeUtils: CoreTimeUtilsProvider, constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private timeUtils: CoreTimeUtilsProvider,
private utils: CoreUtilsProvider) { private utils: CoreUtilsProvider) {
this.logger = logger.getInstance('CoreQuestionProvider'); this.logger = logger.getInstance('CoreQuestionProvider');
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -21,7 +21,7 @@ import { CoreSitesProvider } from '@providers/sites';
import { CoreMimetypeUtilsProvider } from '@providers/utils/mimetype'; import { CoreMimetypeUtilsProvider } from '@providers/utils/mimetype';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { Md5 } from 'ts-md5/dist/md5'; import { Md5 } from 'ts-md5/dist/md5';
import { SQLiteDB } from '@classes/sqlitedb'; import { SQLiteDB, SQLiteDBTableSchema } from '@classes/sqlitedb';
/** /**
* Service to share files with the app. * Service to share files with the app.
@ -32,7 +32,7 @@ export class CoreSharedFilesProvider {
// Variables for the database. // Variables for the database.
protected SHARED_FILES_TABLE = 'shared_files'; protected SHARED_FILES_TABLE = 'shared_files';
protected tableSchema = { protected tableSchema: SQLiteDBTableSchema = {
name: this.SHARED_FILES_TABLE, name: this.SHARED_FILES_TABLE,
columns: [ columns: [
{ {

View File

@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
import { CoreFilepoolProvider } from '@providers/filepool'; import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreLoggerProvider } from '@providers/logger'; import { CoreLoggerProvider } from '@providers/logger';
import { CoreSite } from '@classes/site'; import { CoreSite } from '@classes/site';
import { CoreSitesProvider } from '@providers/sites'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUtilsProvider } from '@providers/utils/utils';
/** /**
@ -31,33 +31,37 @@ export class CoreUserProvider {
// Variables for database. // Variables for database.
protected USERS_TABLE = 'users'; protected USERS_TABLE = 'users';
protected tablesSchema = [ protected siteSchema: CoreSiteSchema = {
{ name: 'CoreUserProvider',
name: this.USERS_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'id', name: this.USERS_TABLE,
type: 'INTEGER', columns: [
primaryKey: true {
}, name: 'id',
{ type: 'INTEGER',
name: 'fullname', primaryKey: true
type: 'TEXT' },
}, {
{ name: 'fullname',
name: 'profileimageurl', type: 'TEXT'
type: 'TEXT' },
} {
] name: 'profileimageurl',
} type: 'TEXT'
]; }
]
}
]
};
protected logger; protected logger;
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider, constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider,
private filepoolProvider: CoreFilepoolProvider) { private filepoolProvider: CoreFilepoolProvider) {
this.logger = logger.getInstance('CoreUserProvider'); this.logger = logger.getInstance('CoreUserProvider');
this.sitesProvider.createTablesFromSchema(this.tablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
} }
/** /**

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreAppProvider } from './app'; import { CoreAppProvider } from './app';
import { SQLiteDB } from '@classes/sqlitedb'; import { SQLiteDB, SQLiteDBTableSchema } from '@classes/sqlitedb';
/** /**
* Factory to provide access to dynamic and permanent config and settings. * Factory to provide access to dynamic and permanent config and settings.
@ -24,7 +24,7 @@ import { SQLiteDB } from '@classes/sqlitedb';
export class CoreConfigProvider { export class CoreConfigProvider {
protected appDB: SQLiteDB; protected appDB: SQLiteDB;
protected TABLE_NAME = 'core_config'; protected TABLE_NAME = 'core_config';
protected tableSchema = { protected tableSchema: SQLiteDBTableSchema = {
name: this.TABLE_NAME, name: this.TABLE_NAME,
columns: [ columns: [
{ {

View File

@ -19,7 +19,7 @@ import { CoreConfigProvider } from './config';
import { CoreLoggerProvider } from './logger'; import { CoreLoggerProvider } from './logger';
import { CoreUtilsProvider } from './utils/utils'; import { CoreUtilsProvider } from './utils/utils';
import { CoreConstants } from '@core/constants'; import { CoreConstants } from '@core/constants';
import { SQLiteDB } from '@classes/sqlitedb'; import { SQLiteDB, SQLiteDBTableSchema } from '@classes/sqlitedb';
/** /**
* Interface that all cron handlers must implement. * Interface that all cron handlers must implement.
@ -94,7 +94,7 @@ export class CoreCronDelegate {
// Variables for database. // Variables for database.
protected CRON_TABLE = 'cron'; protected CRON_TABLE = 'cron';
protected tableSchema = { protected tableSchema: SQLiteDBTableSchema = {
name: this.CRON_TABLE, name: this.CRON_TABLE,
columns: [ columns: [
{ {

View File

@ -20,7 +20,7 @@ import { CoreFileProvider } from './file';
import { CoreInitDelegate } from './init'; import { CoreInitDelegate } from './init';
import { CoreLoggerProvider } from './logger'; import { CoreLoggerProvider } from './logger';
import { CorePluginFileDelegate } from './plugin-file-delegate'; import { CorePluginFileDelegate } from './plugin-file-delegate';
import { CoreSitesProvider } from './sites'; import { CoreSitesProvider, CoreSiteSchema } from './sites';
import { CoreWSProvider } from './ws'; import { CoreWSProvider } from './ws';
import { CoreDomUtilsProvider } from './utils/dom'; import { CoreDomUtilsProvider } from './utils/dom';
import { CoreMimetypeUtilsProvider } from './utils/mimetype'; import { CoreMimetypeUtilsProvider } from './utils/mimetype';
@ -28,7 +28,7 @@ import { CoreTextUtilsProvider } from './utils/text';
import { CoreTimeUtilsProvider } from './utils/time'; import { CoreTimeUtilsProvider } from './utils/time';
import { CoreUrlUtilsProvider } from './utils/url'; import { CoreUrlUtilsProvider } from './utils/url';
import { CoreUtilsProvider } from './utils/utils'; import { CoreUtilsProvider } from './utils/utils';
import { SQLiteDB } from '@classes/sqlitedb'; import { SQLiteDB, SQLiteDBTableSchema } from '@classes/sqlitedb';
import { CoreConstants } from '@core/constants'; import { CoreConstants } from '@core/constants';
import { Md5 } from 'ts-md5/dist/md5'; import { Md5 } from 'ts-md5/dist/md5';
@ -254,7 +254,7 @@ export class CoreFilepoolProvider {
protected FILES_TABLE = 'filepool_files'; // Downloaded files. protected FILES_TABLE = 'filepool_files'; // Downloaded files.
protected LINKS_TABLE = 'filepool_files_links'; // Links between downloaded files and components. protected LINKS_TABLE = 'filepool_files_links'; // Links between downloaded files and components.
protected PACKAGES_TABLE = 'filepool_packages'; // Downloaded packages (sets of files). protected PACKAGES_TABLE = 'filepool_packages'; // Downloaded packages (sets of files).
protected appTablesSchema = [ protected appTablesSchema: SQLiteDBTableSchema[] = [
{ {
name: this.QUEUE_TABLE, name: this.QUEUE_TABLE,
columns: [ columns: [
@ -306,115 +306,119 @@ export class CoreFilepoolProvider {
primaryKeys: ['siteId', 'fileId'] primaryKeys: ['siteId', 'fileId']
} }
]; ];
protected sitesTablesSchema = [ protected siteSchma: CoreSiteSchema = {
{ name: 'CoreFilepoolProvider',
name: this.FILES_TABLE, version: 1,
columns: [ tables: [
{ {
name: 'fileId', name: this.FILES_TABLE,
type: 'TEXT', columns: [
primaryKey: true {
}, name: 'fileId',
{ type: 'TEXT',
name: 'url', primaryKey: true
type: 'TEXT', },
notNull: true {
}, name: 'url',
{ type: 'TEXT',
name: 'revision', notNull: true
type: 'INTEGER' },
}, {
{ name: 'revision',
name: 'timemodified', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'timemodified',
name: 'stale', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'stale',
name: 'downloadTime', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'downloadTime',
name: 'isexternalfile', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'isexternalfile',
name: 'repositorytype', type: 'INTEGER'
type: 'TEXT' },
}, {
{ name: 'repositorytype',
name: 'path', type: 'TEXT'
type: 'TEXT' },
}, {
{ name: 'path',
name: 'extension', type: 'TEXT'
type: 'TEXT' },
} {
] name: 'extension',
}, type: 'TEXT'
{ }
name: this.LINKS_TABLE, ]
columns: [ },
{ {
name: 'fileId', name: this.LINKS_TABLE,
type: 'TEXT' columns: [
}, {
{ name: 'fileId',
name: 'component', type: 'TEXT'
type: 'TEXT' },
}, {
{ name: 'component',
name: 'componentId', type: 'TEXT'
type: 'TEXT' },
} {
], name: 'componentId',
primaryKeys: ['fileId', 'component', 'componentId'] type: 'TEXT'
}, }
{ ],
name: this.PACKAGES_TABLE, primaryKeys: ['fileId', 'component', 'componentId']
columns: [ },
{ {
name: 'id', name: this.PACKAGES_TABLE,
type: 'TEXT', columns: [
primaryKey: true {
}, name: 'id',
{ type: 'TEXT',
name: 'component', primaryKey: true
type: 'TEXT' },
}, {
{ name: 'component',
name: 'componentId', type: 'TEXT'
type: 'TEXT' },
}, {
{ name: 'componentId',
name: 'status', type: 'TEXT'
type: 'TEXT' },
}, {
{ name: 'status',
name: 'previous', type: 'TEXT'
type: 'TEXT' },
}, {
{ name: 'previous',
name: 'updated', type: 'TEXT'
type: 'INTEGER' },
}, {
{ name: 'updated',
name: 'downloadTime', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'downloadTime',
name: 'previousDownloadTime', type: 'INTEGER'
type: 'INTEGER' },
}, {
{ name: 'previousDownloadTime',
name: 'extra', type: 'INTEGER'
type: 'TEXT' },
} {
] name: 'extra',
}, type: 'TEXT'
]; }
]
}
]
};
protected logger; protected logger;
protected appDB: SQLiteDB; protected appDB: SQLiteDB;
@ -443,7 +447,7 @@ export class CoreFilepoolProvider {
this.appDB = this.appProvider.getDB(); this.appDB = this.appProvider.getDB();
this.appDB.createTablesFromSchema(this.appTablesSchema); this.appDB.createTablesFromSchema(this.appTablesSchema);
this.sitesProvider.createTablesFromSchema(this.sitesTablesSchema); this.sitesProvider.registerSiteSchema(this.siteSchma);
initDelegate.ready().then(() => { initDelegate.ready().then(() => {
// Waiting for the app to be ready to start processing the queue. // Waiting for the app to be ready to start processing the queue.

View File

@ -22,7 +22,7 @@ import { CoreEventsProvider } from './events';
import { CoreLoggerProvider } from './logger'; import { CoreLoggerProvider } from './logger';
import { CoreTextUtilsProvider } from './utils/text'; import { CoreTextUtilsProvider } from './utils/text';
import { CoreUtilsProvider } from './utils/utils'; import { CoreUtilsProvider } from './utils/utils';
import { SQLiteDB } from '@classes/sqlitedb'; import { SQLiteDB, SQLiteDBTableSchema } from '@classes/sqlitedb';
import { CoreConstants } from '@core/constants'; import { CoreConstants } from '@core/constants';
import { Subject, Subscription } from 'rxjs'; import { Subject, Subscription } from 'rxjs';
@ -38,7 +38,7 @@ export class CoreLocalNotificationsProvider {
protected SITES_TABLE = 'notification_sites'; // Store to asigne unique codes to each site. protected SITES_TABLE = 'notification_sites'; // Store to asigne unique codes to each site.
protected COMPONENTS_TABLE = 'notification_components'; // Store to asigne unique codes to each component. protected COMPONENTS_TABLE = 'notification_components'; // Store to asigne unique codes to each component.
protected TRIGGERED_TABLE = 'notifications_triggered'; // Store to prevent re-triggering notifications. protected TRIGGERED_TABLE = 'notifications_triggered'; // Store to prevent re-triggering notifications.
protected tablesSchema = [ protected tablesSchema: SQLiteDBTableSchema[] = [
{ {
name: this.SITES_TABLE, name: this.SITES_TABLE,
columns: [ columns: [

View File

@ -25,7 +25,7 @@ import { CoreUtilsProvider } from './utils/utils';
import { CoreConstants } from '@core/constants'; import { CoreConstants } from '@core/constants';
import { CoreConfigConstants } from '../configconstants'; import { CoreConfigConstants } from '../configconstants';
import { CoreSite } from '@classes/site'; import { CoreSite } from '@classes/site';
import { SQLiteDB } from '@classes/sqlitedb'; import { SQLiteDB, SQLiteDBTableSchema } from '@classes/sqlitedb';
import { Md5 } from 'ts-md5/dist/md5'; import { Md5 } from 'ts-md5/dist/md5';
/** /**
@ -127,6 +127,41 @@ export interface CoreSiteBasicInfo {
badge?: number; badge?: number;
} }
/**
* Site schema and migration function.
*/
export interface CoreSiteSchema {
/**
* Name of the schema.
*
* @type {string}
*/
name: string;
/**
* Latest version of the schema (integer greater than 0).
*
* @type {number}
*/
version: number;
/**
* Tables to create when installing or upgrading the schema.
*/
tables?: SQLiteDBTableSchema[];
/**
* Migrates the schema in a site to the latest version.
*
* Called when installing and upgrading the schema, after creating the defined tables.
*
* @param {SQLiteDB} db Site database.
* @param {number} oldVersion Old version of the schema or 0 if not installed.
* @return {Promise<any> | void} Promise resolved when done.
*/
migrate?(db: SQLiteDB, oldVersion: number): Promise<any> | void;
}
/* /*
* Service to manage and interact with sites. * Service to manage and interact with sites.
* It allows creating tables in the databases of all sites. Each service or component should be responsible of creating * It allows creating tables in the databases of all sites. Each service or component should be responsible of creating
@ -143,7 +178,8 @@ export class CoreSitesProvider {
// Variables for the database. // Variables for the database.
protected SITES_TABLE = 'sites'; protected SITES_TABLE = 'sites';
protected CURRENT_SITE_TABLE = 'current_site'; protected CURRENT_SITE_TABLE = 'current_site';
protected appTablesSchema = [ protected SCHEMA_VERSIONS_TABLE = 'schema_versions';
protected appTablesSchema: SQLiteDBTableSchema[] = [
{ {
name: this.SITES_TABLE, name: this.SITES_TABLE,
columns: [ columns: [
@ -208,7 +244,70 @@ export class CoreSitesProvider {
protected currentSite: CoreSite; protected currentSite: CoreSite;
protected sites: { [s: string]: CoreSite } = {}; protected sites: { [s: string]: CoreSite } = {};
protected appDB: SQLiteDB; protected appDB: SQLiteDB;
protected siteTablesSchemas = []; // Schemas for site tables. Other providers can add schemas in here. protected siteSchemasMigration: { [siteId: string]: Promise<any> } = {};
// Schemas for site tables. Other providers can add schemas in here.
protected siteSchemas: { [name: string]: CoreSiteSchema } = {};
protected siteTablesSchemas: SQLiteDBTableSchema[] = [
{
name: this.SCHEMA_VERSIONS_TABLE,
columns: [
{
name: 'name',
type: 'TEXT',
primaryKey: true,
},
{
name: 'version',
type: 'INTEGER'
}
]
}
];
// Site schema for this provider.
protected siteSchema: CoreSiteSchema = {
name: 'CoreSitesProvider',
version: 1,
tables: [
{
name: CoreSite.WS_CACHE_TABLE,
columns: [
{
name: 'id',
type: 'TEXT',
primaryKey: true
},
{
name: 'data',
type: 'TEXT'
},
{
name: 'key',
type: 'TEXT'
},
{
name: 'expirationTime',
type: 'INTEGER'
}
]
},
{
name: CoreSite.CONFIG_TABLE,
columns: [
{
name: 'name',
type: 'TEXT',
unique: true,
notNull: true
},
{
name: 'value'
}
]
}
]
};
constructor(logger: CoreLoggerProvider, private http: HttpClient, private sitesFactory: CoreSitesFactoryProvider, constructor(logger: CoreLoggerProvider, private http: HttpClient, private sitesFactory: CoreSitesFactoryProvider,
private appProvider: CoreAppProvider, private translate: TranslateService, private urlUtils: CoreUrlUtilsProvider, private appProvider: CoreAppProvider, private translate: TranslateService, private urlUtils: CoreUrlUtilsProvider,
@ -218,6 +317,7 @@ export class CoreSitesProvider {
this.appDB = appProvider.getDB(); this.appDB = appProvider.getDB();
this.appDB.createTablesFromSchema(this.appTablesSchema); this.appDB.createTablesFromSchema(this.appTablesSchema);
this.registerSiteSchema(this.siteSchema);
} }
/** /**
@ -478,24 +578,23 @@ export class CoreSitesProvider {
candidateSite.setId(siteId); candidateSite.setId(siteId);
candidateSite.setInfo(info); candidateSite.setInfo(info);
// Try to get the site config. // Create database tables before login and before any WS call.
return this.getSiteConfig(candidateSite).then((config) => { return this.migrateSiteSchemas(candidateSite).then(() => {
candidateSite.setConfig(config);
// Add site to sites list.
this.addSite(siteId, siteUrl, token, info, privateToken, config);
// Turn candidate site into current site.
this.currentSite = candidateSite;
this.sites[siteId] = candidateSite;
// Store session.
this.login(siteId);
this.eventsProvider.trigger(CoreEventsProvider.SITE_ADDED, info, siteId);
if (this.siteTablesSchemas.length) { // Try to get the site config.
// Create tables in the site's database. return this.getSiteConfig(candidateSite).then((config) => {
candidateSite.getDb().createTablesFromSchema(this.siteTablesSchemas); candidateSite.setConfig(config);
} // Add site to sites list.
this.addSite(siteId, siteUrl, token, info, privateToken, config);
// Turn candidate site into current site.
this.currentSite = candidateSite;
this.sites[siteId] = candidateSite;
// Store session.
this.login(siteId);
this.eventsProvider.trigger(CoreEventsProvider.SITE_ADDED, info, siteId);
return siteId; return siteId;
});
}); });
} else if (result == this.LEGACY_APP_VERSION) { } else if (result == this.LEGACY_APP_VERSION) {
let errorKey = 'core.login.legacymoodleversion', let errorKey = 'core.login.legacymoodleversion',
@ -830,10 +929,10 @@ export class CoreSitesProvider {
* Create a site from an entry of the sites list DB. The new site is added to the list of "cached" sites: this.sites. * Create a site from an entry of the sites list DB. The new site is added to the list of "cached" sites: this.sites.
* *
* @param {any} entry Site list entry. * @param {any} entry Site list entry.
* @return {CoreSite} Created site. * @return {Promise<CoreSite>} Promised resolved with the created site.
*/ */
makeSiteFromSiteListEntry(entry: any): CoreSite { makeSiteFromSiteListEntry(entry: any): Promise<CoreSite> {
let site, let site: CoreSite,
info = entry.info, info = entry.info,
config = entry.config; config = entry.config;
@ -843,13 +942,13 @@ export class CoreSitesProvider {
site = this.sitesFactory.makeSite(entry.id, entry.siteUrl, entry.token, site = this.sitesFactory.makeSite(entry.id, entry.siteUrl, entry.token,
info, entry.privateToken, config, entry.loggedOut == 1); info, entry.privateToken, config, entry.loggedOut == 1);
this.sites[entry.id] = site;
if (this.siteTablesSchemas.length) {
// Create tables in the site's database.
site.getDb().createTablesFromSchema(this.siteTablesSchemas);
}
return site; return this.migrateSiteSchemas(site).then(() => {
// Set site after migrating schemas, or a call to getSite could get the site while tables are being created.
this.sites[entry.id] = site;
return site;
});
} }
/** /**
@ -1178,9 +1277,11 @@ export class CoreSitesProvider {
return this.appDB.getAllRecords(this.SITES_TABLE).then((siteEntries) => { return this.appDB.getAllRecords(this.SITES_TABLE).then((siteEntries) => {
const ids = []; const ids = [];
const promises = [];
siteEntries.forEach((site) => { siteEntries.forEach((site) => {
if (!this.sites[site.id]) { if (!this.sites[site.id]) {
this.makeSiteFromSiteListEntry(site); promises.push(this.makeSiteFromSiteListEntry(site));
} }
if (this.sites[site.id].containsUrl(url)) { if (this.sites[site.id].containsUrl(url)) {
@ -1190,7 +1291,9 @@ export class CoreSitesProvider {
} }
}); });
return ids; return Promise.all(promises).then(() => {
return ids;
});
}).catch(() => { }).catch(() => {
// Shouldn't happen. // Shouldn't happen.
return []; return [];
@ -1251,18 +1354,18 @@ export class CoreSitesProvider {
/** /**
* Create a table in all the sites databases. * Create a table in all the sites databases.
* *
* @param {any} table Table schema. * @param {SQLiteDBTamableSchema} table Table schema.
*/ */
createTableFromSchema(table: any): void { createTableFromSchema(table: SQLiteDBTableSchema): void {
this.createTablesFromSchema([table]); this.createTablesFromSchema([table]);
} }
/** /**
* Create several tables in all the sites databases. * Create several tables in all the sites databases.
* *
* @param {any[]} tables List of tables schema. * @param {SQLiteDBTamableSchema[]} tables List of tables schema.
*/ */
createTablesFromSchema(tables: any[]): void { createTablesFromSchema(tables: SQLiteDBTableSchema[]): void {
// Add the tables to the list of schemas. This list is to create all the tables in new sites. // Add the tables to the list of schemas. This list is to create all the tables in new sites.
this.siteTablesSchemas = this.siteTablesSchemas.concat(tables); this.siteTablesSchemas = this.siteTablesSchemas.concat(tables);
@ -1294,4 +1397,70 @@ export class CoreSitesProvider {
isLegacyMoodleByInfo(info: any): boolean { isLegacyMoodleByInfo(info: any): boolean {
return this.isValidMoodleVersion(info) == this.LEGACY_APP_VERSION; return this.isValidMoodleVersion(info) == this.LEGACY_APP_VERSION;
} }
/**
* Register a site schema.
*/
registerSiteSchema(schema: CoreSiteSchema): void {
this.siteSchemas[schema.name] = schema;
}
/**
* Install and upgrade all the registered schemas and tables.
*
* @param {CoreSite} site Site.
* @return {Promise<any>} Promise resolved when done.
*/
migrateSiteSchemas(site: CoreSite): Promise<any> {
const db = site.getDb();
if (this.siteSchemasMigration[site.id]) {
return this.siteSchemasMigration[site.id];
}
this.logger.debug(`Migrating all schemas of ${site.id}`);
// First create tables not registerd with name/version.
const promise = db.createTablesFromSchema(this.siteTablesSchemas).then(() => {
// Fetch installed versions of the schema.
return db.getAllRecords(this.SCHEMA_VERSIONS_TABLE).then((records) => {
const versions = {};
records.forEach((record) => {
versions[record.name] = record.version;
});
const promises = [];
for (const name in this.siteSchemas) {
const schema = this.siteSchemas[name];
const oldVersion = versions[name] || 0;
if (oldVersion >= schema.version) {
continue;
}
this.logger.debug(`Migrating schema '${name}' of ${site.id} from version ${oldVersion} to ${schema.version}`);
let promise: Promise<any> = Promise.resolve();
if (schema.tables) {
promise = promise.then(() => db.createTablesFromSchema(schema.tables));
}
if (schema.migrate) {
promise = promise.then(() => schema.migrate(db, oldVersion));
}
// Set installed version.
promise = promise.then(() => db.insertRecord(this.SCHEMA_VERSIONS_TABLE, {name, version: schema.version}));
promises.push(promise);
}
return Promise.all(promises);
});
});
this.siteSchemasMigration[site.id] = promise;
return promise.finally(() => {
delete this.siteSchemasMigration[site.id];
});
}
} }

View File

@ -14,7 +14,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { CoreEventsProvider } from './events'; import { CoreEventsProvider } from './events';
import { CoreSitesProvider } from './sites'; import { CoreSitesProvider, CoreSiteSchema } from './sites';
/* /*
* Service that provides some features regarding synchronization. * Service that provides some features regarding synchronization.
@ -24,36 +24,42 @@ export class CoreSyncProvider {
// Variables for the database. // Variables for the database.
protected SYNC_TABLE = 'sync'; protected SYNC_TABLE = 'sync';
protected tableSchema = { protected siteSchema: CoreSiteSchema = {
name: this.SYNC_TABLE, name: 'CoreSyncProvider',
columns: [ version: 1,
tables: [
{ {
name: 'component', name: this.SYNC_TABLE,
type: 'TEXT', columns: [
notNull: true {
}, name: 'component',
{ type: 'TEXT',
name: 'id', notNull: true
type: 'TEXT', },
notNull: true {
}, name: 'id',
{ type: 'TEXT',
name: 'time', notNull: true
type: 'INTEGER' },
}, {
{ name: 'time',
name: 'warnings', type: 'INTEGER'
type: 'TEXT' },
{
name: 'warnings',
type: 'TEXT'
}
],
primaryKeys: ['component', 'id']
} }
], ]
primaryKeys: ['component', 'id']
}; };
// Store blocked sync objects. // Store blocked sync objects.
protected blockedItems: { [siteId: string]: { [blockId: string]: { [operation: string]: boolean } } } = {}; protected blockedItems: { [siteId: string]: { [blockId: string]: { [operation: string]: boolean } } } = {};
constructor(eventsProvider: CoreEventsProvider, private sitesProvider: CoreSitesProvider) { constructor(eventsProvider: CoreEventsProvider, private sitesProvider: CoreSitesProvider) {
this.sitesProvider.createTableFromSchema(this.tableSchema); this.sitesProvider.registerSiteSchema(this.siteSchema);
// Unblock all blocks on logout. // Unblock all blocks on logout.
eventsProvider.on(CoreEventsProvider.LOGOUT, (data) => { eventsProvider.on(CoreEventsProvider.LOGOUT, (data) => {

View File

@ -4,6 +4,7 @@ information provided here is intended especially for developers.
=== 3.6.1 === === 3.6.1 ===
- The local notifications plugin was updated to its latest version. The new API has some breaking changes, so please check its documentation if you're using local notifications. Also, you need to run "npm install" to update the ionic-native library. - The local notifications plugin was updated to its latest version. The new API has some breaking changes, so please check its documentation if you're using local notifications. Also, you need to run "npm install" to update the ionic-native library.
- New method CoreSitesProvider.registerSiteSchema allows to register table schemas and migration functions for site databases. Prefer this method over CoreSitesProvider.createTablesFromSchema: it supports schema migrations and it tracks the installed version of the schema, so it does not try to create the tables on every app boot.
=== 3.6.0 === === 3.6.0 ===