diff --git a/.gitignore b/.gitignore
index 92a4fa38..3f757471 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
/application/config/database.php
/application/config/config.php
+/uploads/*.adi
diff --git a/application/config/config.sample.php b/application/config/config.sample.php
index b0be7d88..254ed3b4 100644
--- a/application/config/config.sample.php
+++ b/application/config/config.sample.php
@@ -60,7 +60,7 @@ $config['auth_level'][99] = "Administrator";
|--------------------------------------------------------------------------
|
| 'username' QRZ.com Username
-| 'password' Default locator used to calculate bearings/distance
+| 'password' QRZ.com Password
*/
$config['qrz_username'] = "";
diff --git a/application/config/migration.php b/application/config/migration.php
new file mode 100644
index 00000000..93759a4f
--- /dev/null
+++ b/application/config/migration.php
@@ -0,0 +1,41 @@
+migration->latest() this is the version that schema will
+| be upgraded / downgraded to.
+|
+*/
+$config['migration_version'] = 2;
+
+
+/*
+|--------------------------------------------------------------------------
+| Migrations Path
+|--------------------------------------------------------------------------
+|
+| Path to your migrations folder.
+| Typically, it will be within your application path.
+| Also, writing permission is required within the migrations path.
+|
+*/
+$config['migration_path'] = APPPATH . 'migrations/';
+
+
+/* End of file migration.php */
+/* Location: ./application/config/migration.php */
diff --git a/application/controllers/dashboard.php b/application/controllers/dashboard.php
index d7c8c0ee..2226f9b0 100644
--- a/application/controllers/dashboard.php
+++ b/application/controllers/dashboard.php
@@ -11,7 +11,10 @@ class Dashboard extends CI_Controller {
public function index()
{
-
+ // Check our version and run any migrations
+ $this->load->library('Migration');
+ $this->migration->current();
+
// Database connections
$this->load->model('logbook_model');
$this->load->model('user_model');
@@ -162,4 +165,4 @@ class Dashboard extends CI_Controller {
}
-}
\ No newline at end of file
+}
diff --git a/application/controllers/lotw.php b/application/controllers/lotw.php
index c9c254d3..b9eefd75 100644
--- a/application/controllers/lotw.php
+++ b/application/controllers/lotw.php
@@ -11,95 +11,160 @@ class Lotw extends CI_Controller {
$this->load->model('user_model');
if(!$this->user_model->authorize(2)) { $this->session->set_flashdata('notice', 'You\'re not allowed to do that!'); redirect('dashboard'); }
}
+
+ private function loadFromFile($filepath)
+ {
+ // Figure out how we should be marking QSLs confirmed via LoTW
+ $query = $query = $this->db->query('SELECT lotw_rcvd_mark FROM config');
+ $q = $query->row();
+ $config['lotw_rcvd_mark'] = $q->lotw_rcvd_mark;
+
+ ini_set('memory_limit', '-1');
+ set_time_limit(0);
+
+ $this->load->library('adif_parser');
+
+ $this->adif_parser->load_from_file($filepath);
+
+ $this->adif_parser->initialize();
+
+ $table = "
-
Upload the Exported ADIF file from LoTW from the Download Report Area, to mark QSOs as confirmed on LOTW.
-
-
Important Log files must have the file type .adi
-
-
-
-
-
-
-
+
+
diff --git a/application/views/qso/edit.php b/application/views/qso/edit.php
index 0f2ec5c2..447689ed 100755
--- a/application/views/qso/edit.php
+++ b/application/views/qso/edit.php
@@ -159,8 +159,8 @@
>No
>Yes
>Requested
-
>Invalid (Ignore)
-
>Verified (Match)
+
>Invalid (Ignore)
+
>Verified (Match)
@@ -203,8 +203,8 @@
>No
>Yes
>Requested
- >Invalid (Ignore)
- >Verified (Match)
+ >Invalid (Ignore)
+ >Verified (Match)
@@ -225,8 +225,8 @@
>No
>Yes
>Requested
-
>Invalid (Ignore)
-
>Verified (Match)
+
>Invalid (Ignore)
+
>Verified (Match)
diff --git a/application/views/user/edit.php b/application/views/user/edit.php
index 8692c20d..0efff654 100644
--- a/application/views/user/edit.php
+++ b/application/views/user/edit.php
@@ -85,6 +85,20 @@ $this->load->helper('form');
+
+ Logbook of The World (LoTW) Username
+
+ ".$userlotwname_error.""; } ?>
+
+
+
+
+ Logbook of The World (LoTW) Password
+
+ ".$lotwpassword_error.""; } else { ?>
+ Leave blank to keep existing password
+
+
diff --git a/install/assets/install.sql b/install/assets/install.sql
old mode 100644
new mode 100755
index 02b8fdf6..de7ec395
--- a/install/assets/install.sql
+++ b/install/assets/install.sql
@@ -3815,6 +3815,8 @@ CREATE TABLE IF NOT EXISTS `users` (
`user_locator` varchar(255) NOT NULL,
`user_firstname` varchar(255) NOT NULL,
`user_lastname` varchar(255) NOT NULL,
+ `user_lotw_name` varchar(32) NULL COMMENT 'LoTW Username',
+ `user_lotw_password` varchar(64) NULL COMMENT 'LoTW Password',
PRIMARY KEY (`user_id`),
UNIQUE KEY `user_name` (`user_name`),
UNIQUE KEY `user_email` (`user_email`)
diff --git a/system/language/english/migration_lang.php b/system/language/english/migration_lang.php
new file mode 100644
index 00000000..fdf36ee9
--- /dev/null
+++ b/system/language/english/migration_lang.php
@@ -0,0 +1,13 @@
+ $val)
+ {
+ $this->{'_' . $key} = $val;
+ }
+
+ log_message('debug', 'Migrations class initialized');
+
+ // Are they trying to use migrations while it is disabled?
+ if ($this->_migration_enabled !== TRUE)
+ {
+ show_error('Migrations has been loaded but is disabled or set up incorrectly.');
+ }
+
+ // If not set, set it
+ $this->_migration_path == '' AND $this->_migration_path = APPPATH . 'migrations/';
+
+ // Add trailing slash if not set
+ $this->_migration_path = rtrim($this->_migration_path, '/').'/';
+
+ // Load migration language
+ $this->lang->load('migration');
+
+ // They'll probably be using dbforge
+ $this->load->dbforge();
+
+ // If the migrations table is missing, make it
+ if ( ! $this->db->table_exists('migrations'))
+ {
+ $this->dbforge->add_field(array(
+ 'version' => array('type' => 'INT', 'constraint' => 3),
+ ));
+
+ $this->dbforge->create_table('migrations', TRUE);
+
+ $this->db->insert('migrations', array('version' => 0));
+ }
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Migrate to a schema version
+ *
+ * Calls each migration step required to get to the schema version of
+ * choice
+ *
+ * @param int Target schema version
+ * @return mixed TRUE if already latest, FALSE if failed, int if upgraded
+ */
+ public function version($target_version)
+ {
+ $start = $current_version = $this->_get_version();
+ $stop = $target_version;
+
+ if ($target_version > $current_version)
+ {
+ // Moving Up
+ ++$start;
+ ++$stop;
+ $step = 1;
+ }
+ else
+ {
+ // Moving Down
+ $step = -1;
+ }
+
+ $method = ($step === 1) ? 'up' : 'down';
+ $migrations = array();
+
+ // We now prepare to actually DO the migrations
+ // But first let's make sure that everything is the way it should be
+ for ($i = $start; $i != $stop; $i += $step)
+ {
+ $f = glob(sprintf($this->_migration_path . '%03d_*.php', $i));
+
+ // Only one migration per step is permitted
+ if (count($f) > 1)
+ {
+ $this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $i);
+ return FALSE;
+ }
+
+ // Migration step not found
+ if (count($f) == 0)
+ {
+ // If trying to migrate up to a version greater than the last
+ // existing one, migrate to the last one.
+ if ($step == 1)
+ {
+ break;
+ }
+
+ // If trying to migrate down but we're missing a step,
+ // something must definitely be wrong.
+ $this->_error_string = sprintf($this->lang->line('migration_not_found'), $i);
+ return FALSE;
+ }
+
+ $file = basename($f[0]);
+ $name = basename($f[0], '.php');
+
+ // Filename validations
+ if (preg_match('/^\d{3}_(\w+)$/', $name, $match))
+ {
+ $match[1] = strtolower($match[1]);
+
+ // Cannot repeat a migration at different steps
+ if (in_array($match[1], $migrations))
+ {
+ $this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $match[1]);
+ return FALSE;
+ }
+
+ include $f[0];
+ $class = 'Migration_' . ucfirst($match[1]);
+
+ if ( ! class_exists($class))
+ {
+ $this->_error_string = sprintf($this->lang->line('migration_class_doesnt_exist'), $class);
+ return FALSE;
+ }
+
+ if ( ! is_callable(array($class, $method)))
+ {
+ $this->_error_string = sprintf($this->lang->line('migration_missing_'.$method.'_method'), $class);
+ return FALSE;
+ }
+
+ $migrations[] = $match[1];
+ }
+ else
+ {
+ $this->_error_string = sprintf($this->lang->line('migration_invalid_filename'), $file);
+ return FALSE;
+ }
+ }
+
+ log_message('debug', 'Current migration: ' . $current_version);
+
+ $version = $i + ($step == 1 ? -1 : 0);
+
+ // If there is nothing to do so quit
+ if ($migrations === array())
+ {
+ return TRUE;
+ }
+
+ log_message('debug', 'Migrating from ' . $method . ' to version ' . $version);
+
+ // Loop through the migrations
+ foreach ($migrations AS $migration)
+ {
+ // Run the migration class
+ $class = 'Migration_' . ucfirst(strtolower($migration));
+ call_user_func(array(new $class, $method));
+
+ $current_version += $step;
+ $this->_update_version($current_version);
+ }
+
+ log_message('debug', 'Finished migrating to '.$current_version);
+
+ return $current_version;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Set's the schema to the latest migration
+ *
+ * @return mixed true if already latest, false if failed, int if upgraded
+ */
+ public function latest()
+ {
+ if ( ! $migrations = $this->find_migrations())
+ {
+ $this->_error_string = $this->line->lang('migration_none_found');
+ return false;
+ }
+
+ $last_migration = basename(end($migrations));
+
+ // Calculate the last migration step from existing migration
+ // filenames and procceed to the standard version migration
+ return $this->version((int) substr($last_migration, 0, 3));
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Set's the schema to the migration version set in config
+ *
+ * @return mixed true if already current, false if failed, int if upgraded
+ */
+ public function current()
+ {
+ return $this->version($this->_migration_version);
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Error string
+ *
+ * @return string Error message returned as a string
+ */
+ public function error_string()
+ {
+ return $this->_error_string;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Set's the schema to the latest migration
+ *
+ * @return mixed true if already latest, false if failed, int if upgraded
+ */
+ protected function find_migrations()
+ {
+ // Load all *_*.php files in the migrations path
+ $files = glob($this->_migration_path . '*_*.php');
+ $file_count = count($files);
+
+ for ($i = 0; $i < $file_count; $i++)
+ {
+ // Mark wrongly formatted files as false for later filtering
+ $name = basename($files[$i], '.php');
+ if ( ! preg_match('/^\d{3}_(\w+)$/', $name))
+ {
+ $files[$i] = FALSE;
+ }
+ }
+
+ sort($files);
+ return $files;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Retrieves current schema version
+ *
+ * @return int Current Migration
+ */
+ protected function _get_version()
+ {
+ $row = $this->db->get('migrations')->row();
+ return $row ? $row->version : 0;
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Stores the current schema version
+ *
+ * @param int Migration reached
+ * @return bool
+ */
+ protected function _update_version($migrations)
+ {
+ return $this->db->update('migrations', array(
+ 'version' => $migrations
+ ));
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * Enable the use of CI super-global
+ *
+ * @param mixed $var
+ * @return mixed
+ */
+ public function __get($var)
+ {
+ return get_instance()->$var;
+ }
+}
+
+/* End of file Migration.php */
+/* Location: ./system/libraries/Migration.php */
diff --git a/uploads/lotwreport.adi b/uploads/lotwreport.adi
deleted file mode 100644
index 7619cb17..00000000
--- a/uploads/lotwreport.adi
+++ /dev/null
@@ -1,31495 +0,0 @@
-ARRL Logbook of the World Status Report
-Generated at 2013-02-15 18:25:43
-for 2e0sql
-Query:
- OWNCALL: 2E0SQL
- QSL ONLY: YES
- QSL SINCE: 2011-04-20 00:00:00
-
-
LoTW
-2013-02-14 19:40:58
-
-1993
-
-
-
-2E0SQL
-2E0SQL
-G7VJR
-80M
-CW
-20120108
-145206
-Y
-20130214
-223
-G7
-JO02af
-
-
-2E0SQL
-2E0SQL
-LY7A
-20M
-SSB
-20120317
-160700
-Y
-20130214
-146
-LY7
-15
-29
-KO14xv
-
-
-2E0SQL
-2E0SQL
-LY7A
-10M
-CW
-20120527
-120429
-Y
-20130214
-146
-LY7
-15
-29
-KO14xv
-
-
-2E0SQL
-2E0SQL
-M0IAA
-80M
-SSB
-20120711
-192900
-Y
-20130214
-223
-M0
-14
-27
-IO93fp
-
-
-2E0SQL
-2E0SQL
-EA3GHZ
-15M
-SSB
-20110519
-125501
-Y
-20130213
-281
-EA3
-14
-37
-JN00ho
-
-
-2E0SQL
-2E0SQL
-VA3MJR
-40M
-JT65
-20121214
-233900
-Y
-20130208
-1
-VA3
-4
-4
-FN03bf
-ON
-
-
-2E0SQL
-2E0SQL
-IK2HDF
-6M
-CW
-20110520
-162107
-Y
-20130207
-248
-IK2
-28
-15
-JN45ia
-
-
-2E0SQL
-2E0SQL
-RA4HL
-20M
-RTTY
-20111112
-164353
-Y
-20130206
-54
-RA4
-16
-29
-LO43fd
-
-
-2E0SQL
-2E0SQL
-TM0HQ
-40M
-SSB
-20120714
-163500
-Y
-20130205
-227
-TM0
-14
-27
-
-
-2E0SQL
-2E0SQL
-IT9TYR
-6M
-SSB
-20120508
-171318
-Y
-20130205
-248
-IT9
-15
-28
-EU-025
-JM78qf
-
-
-2E0SQL
-2E0SQL
-SQ8JX
-20M
-SSB
-20120317
-164500
-Y
-20130205
-269
-SQ8
-15
-28
-
-
-2E0SQL
-2E0SQL
-PA2DKW
-40M
-SSB
-20110601
-221736
-Y
-20130203
-263
-PA2
-14
-27
-JO22ia
-
-
-2E0SQL
-2E0SQL
-IK0YUT
-15M
-SSB
-20121027
-150600
-Y
-20130203
-248
-IK0
-14
-28
-JN63ee
-
-
-2E0SQL
-2E0SQL
-KB0MDQ
-20M
-JT65
-20120615
-234900
-Y
-20130202
-291
-KB0
-EN26uk
-MN
-MN,CROW WING
-
-
-2E0SQL
-2E0SQL
-LY7Z
-20M
-SSB
-20121027
-105200
-Y
-20130129
-146
-LY7
-15
-29
-KO16ja
-
-
-2E0SQL
-2E0SQL
-OM7YC
-20M
-PSK63
-20120204
-163015
-Y
-20130129
-504
-OM7
-15
-28
-JN98si
-
-
-2E0SQL
-2E0SQL
-LY7Z
-20M
-CW
-20121125
-164818
-Y
-20130127
-146
-LY7
-