using System; using System.Text; using System.Linq; using Microsoft.EntityFrameworkCore; using rockfishCore.Models; namespace rockfishCore.Util { //Key generator controller public static class RfSchema { private static rockfishContext ctx; ///////////////////////////////////////////////////////////////// /////////// CHANGE THIS ON NEW SCHEMA UPDATE //////////////////// public const int DESIRED_SCHEMA_LEVEL = 18; ///////////////////////////////////////////////////////////////// static int startingSchema = -1; static int currentSchema = -1; //check and update schema public static void CheckAndUpdate(rockfishContext context) { ctx = context; bool rfSetExists = false; //update schema here? using (var command = ctx.Database.GetDbConnection().CreateCommand()) { //first of all, do we have a schema table yet (v0?) command.CommandText = "SELECT name FROM sqlite_master WHERE type='table' AND name='rfset';"; ctx.Database.OpenConnection(); using (var result = command.ExecuteReader()) { if (result.HasRows) { rfSetExists = true; } ctx.Database.CloseConnection(); } } //Create schema table (v1) if (!rfSetExists) { //nope, no schema table, add it now and set to v1 using (var cmCreateRfSet = ctx.Database.GetDbConnection().CreateCommand()) { context.Database.OpenConnection(); //first of all, do we have a schema table yet (v0?) cmCreateRfSet.CommandText = "CREATE TABLE rfset (id INTEGER PRIMARY KEY, schema INTEGER NOT NULL);"; cmCreateRfSet.ExecuteNonQuery(); cmCreateRfSet.CommandText = "insert into rfset (schema) values (1);"; cmCreateRfSet.ExecuteNonQuery(); context.Database.CloseConnection(); startingSchema = 1; currentSchema = 1; } } else { //get current schema level using (var cm = ctx.Database.GetDbConnection().CreateCommand()) { cm.CommandText = "SELECT schema FROM rfset WHERE id=1;"; ctx.Database.OpenConnection(); using (var result = cm.ExecuteReader()) { if (result.HasRows) { result.Read(); currentSchema = startingSchema = result.GetInt32(0); ctx.Database.CloseConnection(); } else { ctx.Database.CloseConnection(); throw new System.Exception("rockfish->RfSchema->CheckAndUpdate: Error reading schema version"); } } } } //Bail early no update? if (currentSchema == DESIRED_SCHEMA_LEVEL) return; //************* SCHEMA UPDATES ****************** ////////////////////////////////////////////////// //schema 2 case 3283 if (currentSchema < 2) { //add renewal flag to purchase exec("alter table purchase add renewNoticeSent boolean default 0 NOT NULL CHECK (renewNoticeSent IN (0,1))"); //Add product table with prices exec("CREATE TABLE product (id INTEGER PRIMARY KEY, name text not null, productCode text, price integer, renewPrice integer )"); currentSchema = 2; setSchemaLevel(currentSchema); } ////////////////////////////////////////////////// //schema 3 case 3283 if (currentSchema < 3) { //add products current as of 2017-July-18 exec("insert into product (name, productCode, price, renewPrice) values ('Key administration','300093112',3500, 3500);"); exec("insert into product (name, productCode, price, renewPrice) values ('Custom work','300151145',0, 0);"); exec("insert into product (name, productCode, price, renewPrice) values ('AyaNova RI sub (old / unused?)','300740314',19900, 6965);"); exec("insert into product (name, productCode, price, renewPrice) values ('Single AyaNova schedulable resource 1 year subscription license','300740315',15900, 5565);"); exec("insert into product (name, productCode, price, renewPrice) values ('Single AyaNova Lite 1 year subscription license','300740316',6900, 2415);"); exec("insert into product (name, productCode, price, renewPrice) values ('Up to 5 AyaNova schedulable resource 1 year subscription license','300740317', 69500, 24325);"); exec("insert into product (name, productCode, price, renewPrice) values ('Up to 10 AyaNova schedulable resource 1 year subscription license','300740318',119000, 41650);"); exec("insert into product (name, productCode, price, renewPrice) values ('Up to 20 AyaNova schedulable resource 1 year subscription license','300740319',198000, 69300);"); exec("insert into product (name, productCode, price, renewPrice) values ('AyaNova WBI (web browser interface) 1 year subscription license','300740321',9900, 3465);"); exec("insert into product (name, productCode, price, renewPrice) values ('AyaNova MBI (minimal browser interface) 1 year subscription license','300740322', 9900, 3465);"); exec("insert into product (name, productCode, price, renewPrice) values ('AyaNova QBI(QuickBooks interface) 1 year subscription license','300740323',9900, 3465);"); exec("insert into product (name, productCode, price, renewPrice) values ('AyaNova PTI(US Peachtree/Sage 50 interface) 1 year subscription license','300740324',9900, 3465);"); exec("insert into product (name, productCode, price, renewPrice) values ('AyaNova OLI(Outlook interface) 1 year subscription license','300740325',9900, 3465);"); exec("insert into product (name, productCode, price, renewPrice) values ('Plug-in Outlook Schedule Export 1 year subscription license','300740326',1900, 665);"); exec("insert into product (name, productCode, price, renewPrice) values ('Plug-in Export to XLS 1 year subscription license','300740327',1900, 665);"); exec("insert into product (name, productCode, price, renewPrice) values ('Plug-in Quick Notification 1 year subscription license','300740328',1900, 665);"); exec("insert into product (name, productCode, price, renewPrice) values ('Plug-in importexport.csv duplicate 1 year subscription license','300740329',1900, 665);"); exec("insert into product (name, productCode, price, renewPrice) values ('Up to 999 AyaNova schedulable resource 1 year subscription license','300741264',15000, 5250);"); currentSchema = 3; setSchemaLevel(currentSchema); } ////////////////////////////////////////////////// //schema 4 case 3283 if (currentSchema < 4) { //Add template table to store email and other templates exec("CREATE TABLE texttemplate (id INTEGER PRIMARY KEY, name text not null, template text)"); currentSchema = 4; setSchemaLevel(currentSchema); } ////////////////////////////////////////////////// //schema 5 case 3253 if (currentSchema < 5) { exec("alter table customer add active boolean default 1 NOT NULL CHECK (active IN (0,1))"); currentSchema = 5; setSchemaLevel(currentSchema); } ////////////////////////////////////////////////// //schema 6 case 3308 if (currentSchema < 6) { exec("CREATE TABLE rfcaseproject (id INTEGER PRIMARY KEY, name text not null)"); exec("CREATE TABLE rfcase (id INTEGER PRIMARY KEY, title text not null, rfcaseprojectid integer not null, " + "priority integer default 3 NOT NULL CHECK (priority IN (1,2,3,4,5)), notes text, dtcreated integer, dtclosed integer, " + "releaseversion text, releasenotes text, " + "FOREIGN KEY (rfcaseprojectid) REFERENCES rfcaseproject(id))"); exec("CREATE TABLE rfcaseblob (id INTEGER PRIMARY KEY, rfcaseid integer not null, name text not null, file blob not null, " + "FOREIGN KEY (rfcaseid) REFERENCES rfcase(id) ON DELETE CASCADE )"); currentSchema = 6; setSchemaLevel(currentSchema); } ////////////////////////////////////////////////// //schema 7 case 3308 if (currentSchema < 7) { //empty any prior import data exec("delete from rfcaseblob"); exec("delete from rfcase"); exec("delete from rfcaseproject"); //Trigger import of all fogbugz cases into rockfish Util.FBImporter.Import(ctx); //now get rid of the delete records exec("delete from rfcase where title='deleted from FogBugz'"); currentSchema = 7;//<<-------------------- TESTING, CHANGE TO 7 BEFORE PRODUCTION setSchemaLevel(currentSchema); } ////////////////////////////////////////////////// //schema 8 if (currentSchema < 8) { exec("alter table user add dlkey text"); currentSchema = 8; setSchemaLevel(currentSchema); } ////////////////////////////////////////////////// //schema 9 if (currentSchema < 9) { exec("alter table user add dlkeyexp integer"); currentSchema = 9; setSchemaLevel(currentSchema); } ////////////////////////////////////////////////// //schema 10 case 3233 if (currentSchema < 10) { exec("CREATE TABLE license (" + "id INTEGER PRIMARY KEY, dtcreated integer not null, customerid integer not null, regto text not null, key text not null, code text not null, email text not null, " + "fetchfrom text, dtfetched integer, fetched boolean default 0 NOT NULL CHECK (fetched IN (0,1))" + ")"); currentSchema = 10; setSchemaLevel(currentSchema); } ////////////////////////////////////////////////// //schema 11 case 3550 if (currentSchema < 11) { //add 15 level product code exec("insert into product (name, productCode, price, renewPrice) values ('Up to 15 AyaNova schedulable resource 1 year subscription license','300807973',165000, 57750);"); currentSchema = 11; setSchemaLevel(currentSchema); } ////////////////////////////////////////////////// //schema 12 if (currentSchema < 12) { exec("alter table customer add supportEmail text"); exec("alter table customer add adminEmail text"); currentSchema = 12; setSchemaLevel(currentSchema); } ////////////////////////////////////////////////// //schema 13 if (currentSchema < 13) { //Put all the purchase emails into the customer adminEmail field as CSV //These will get all notification types foreach (var purchase in ctx.Purchase.AsNoTracking()) { if (!string.IsNullOrWhiteSpace(purchase.Email)) { var cust = ctx.Customer.SingleOrDefault(m => m.Id == purchase.CustomerId); if (cust == null) { throw new ArgumentNullException($"RFSCHEMA UPDATE 13 (purchases) CUSTOMER {purchase.CustomerId.ToString()} not found!!"); } var purchaseEmails = purchase.Email.Split(","); foreach (var email in purchaseEmails) { Util.CustomerUtils.AddAdminEmailIfNotPresent(cust, email); } ctx.SaveChanges(); } } // //Put all the contact emails into the customer adminEmail field and the support field as CSV // //These will get all notification types // foreach (var contact in ctx.Contact.AsNoTracking()) // { // if (!string.IsNullOrWhiteSpace(contact.Email)) // { // var cust = ctx.Customer.SingleOrDefault(m => m.Id == contact.CustomerId); // if (cust == null) // { // throw new ArgumentNullException($"RFSCHEMA UPDATE 13 (contacts) CUSTOMER {contact.CustomerId.ToString()} not found!!"); // } // var contactEmails = contact.Email.Split(","); // foreach (var email in contactEmails) // { // Util.CustomerUtils.AddAdminEmailIfNotPresent(cust, email); // } // ctx.SaveChanges(); // } // } // //Put all the incident emails into the customer supportEmail field unless already in teh admin field or support field field and the support field as CSV // //These will get only support related (updates/bug reports) notification types // foreach (var incident in ctx.Incident.AsNoTracking()) // { // if (!string.IsNullOrWhiteSpace(incident.Email)) // { // var cust = ctx.Customer.SingleOrDefault(m => m.Id == incident.CustomerId); // if (cust == null) // { // throw new ArgumentNullException($"RFSCHEMA UPDATE 13 (incidents) CUSTOMER {incident.CustomerId.ToString()} not found!!"); // } // var incidentEmails = incident.Email.Split(","); // foreach (var email in incidentEmails) // { // //See if incident email is already in adminEmail field: // if (cust.AdminEmail != null && cust.AdminEmail.ToLowerInvariant().Contains(email.Trim().ToLowerInvariant())) // { // continue;//skip this one, it's already there // } // //It's not in the adminEmail field already so add it to the supportEmail // //field (assumption: all incidents are support related and particularly ones that are not already in admin) // Util.CustomerUtils.AddSupportEmailIfNotPresent(cust, email); // } // ctx.SaveChanges(); // } // } //NOTE: NOTIFICATION AND TRIAL tables have emails but they are dupes, empty or not required based on actual data so not going to import them currentSchema = 13; setSchemaLevel(currentSchema); } ////////////////////////////////////////////////// //schema 14 if (currentSchema < 14) { exec("update license set fetchfrom = 'redacted'"); currentSchema = 14; setSchemaLevel(currentSchema); } ////////////////////////////////////////////////// //schema 15 if (currentSchema < 15) { exec("drop table contact"); exec("drop table incident"); exec("drop table notification"); exec("drop table trial"); currentSchema = 15; setSchemaLevel(currentSchema); } ////////////////////////////////////////////////// //schema 16 RAVEN stuff if (currentSchema < 16) { exec("CREATE TABLE trialrequest (" + "id INTEGER PRIMARY KEY, dbid text not null, companyname text not null, contactname text not null, notes text, email text not null, " + "emailconfirmcode text not null, emailvalidated boolean default 0 NOT NULL CHECK (emailvalidated IN (0,1)), dtrequested integer, " + "dtprocessed integer, status integer default 0 not null, rejectreason text, key text, dtfetched integer" + ")"); exec("alter table site add legacyv7 boolean default 0 NOT NULL CHECK (legacyv7 IN (0,1))"); exec("alter table site add dbid text default 'v7_no_dbid' NOT NULL"); exec("update site set legacyv7 = 1"); exec("alter table license add dbid text default 'v7_no_dbid' NOT NULL"); exec("alter table license add siteid integer"); exec("alter table license add dtLicenseExpiration integer"); exec("alter table license add dtMaintenanceExpiration integer"); exec("alter table purchase add quantity integer default 1 not null"); exec("insert into product (name, productCode, price, renewPrice) values ('TEST RAVEN schedulable resource 1 year subscription license','testfeatscheduser',15900, 5565);"); exec("insert into product (name, productCode, price, renewPrice) values ('TEST RAVEN Accounting 1 year subscription license','testfeatacct',15000, 5250);"); exec("insert into product (name, productCode, price, renewPrice) values ('TEST RAVEN Feature Trial mode','testfeattrial',0, 0);"); exec("insert into product (name, productCode, price, renewPrice) values ('TEST RAVEN Feature Service mode','testfeatservice',0, 0);"); currentSchema = 16; setSchemaLevel(currentSchema); } ////////////////////////////////////////////////// //schema 17 RAVEN Subscription license stuff if (currentSchema < 17) { exec("alter table trialrequest add perpetual boolean default 0 NOT NULL CHECK (perpetual IN (0,1))"); exec("alter table license add perpetual boolean default 0 NOT NULL CHECK (perpetual IN (0,1))"); exec("update license set perpetual = 1");//all the original ones sb perpetual //get rid of test products (which I never used anyway) exec("delete from product where productCode like 'testfeat%'"); exec("insert into product (name, productCode, price, renewPrice) values ('Single AyaNova service techncian perpetual license','301028314',135, 100);"); exec("insert into product (name, productCode, price, renewPrice) values ('Single AyaNova service techncian 1 year maintenance plan - new','301028317',135, 100);"); exec("insert into product (name, productCode, price, renewPrice) values ('Single AyaNova service techncian 1 year maintenance plan - active','301028315',100, 100);"); currentSchema = 17; setSchemaLevel(currentSchema); } ////////////////////////////////////////////////// //schema 18 Shareit notifications if (currentSchema < 18) { exec("CREATE TABLE vendornotification (" + "id INTEGER PRIMARY KEY, dtcreated integer not null, vendor text not null, data text not null, dtprocessed integer, processed boolean default 0 NOT NULL CHECK (processed IN (0,1))" + ")"); currentSchema = 18; setSchemaLevel(currentSchema); } //************************************************************************************* }//eofunction private static void setSchemaLevel(int nCurrentSchema) { exec("UPDATE RFSET SET schema=" + nCurrentSchema.ToString()); } //execute command query private static void exec(string q) { using (var cmCreateRfSet = ctx.Database.GetDbConnection().CreateCommand()) { ctx.Database.OpenConnection(); cmCreateRfSet.CommandText = q; cmCreateRfSet.ExecuteNonQuery(); ctx.Database.CloseConnection(); } } //eoclass } //eons }