Delete files
[foocorp:gnu-fm.git] / nixtape / 1.x / install.php
1 <?php
2
3 /* GNUkebox -- a free software server for recording your listening habits
4
5    Copyright (C) 2009 Free Software Foundation, Inc
6
7    This program is free software: you can redistribute it and/or modify
8    it under the terms of the GNU Affero General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU Affero General Public License for more details.
16
17    You should have received a copy of the GNU Affero General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20 */
21
22 require_once('adodb/adodb-exceptions.inc.php');
23 require_once('adodb/adodb.inc.php');
24 require_once('version.php');
25 require_once('utils/get_absolute_url.php');
26
27 if (file_exists('config.php')) {
28         die('A configuration file already exists. Please delete <i>config.php</i> if you wish to reinstall.');
29 }
30
31 if (isset($_POST['install'])) {
32
33         //Get the database connection string
34         $dbms = $_POST['dbms'];
35         if ($dbms == 'sqlite') {
36                 $filename = urlencode($_POST['filename']);
37                 $connect_string = 'sqlite://' . $filename;
38         } else {
39                 $connect_string = $dbms . '://' . $_POST['username'] . ':' . $_POST['password'] . '@' . $_POST['hostname'] . ':' . $_POST['port'] . '/' . $_POST['dbname'];
40         }
41
42         $adodb_connect_string = str_replace('pgsql:', 'postgres:', $connect_string);
43
44         try {
45                 $adodb =& NewADOConnection($adodb_connect_string);
46         } catch (Exception $e) {
47                 var_dump($e);
48                 adodb_backtrace($e->gettrace());
49                 die("Database connection failure\n");
50         }
51
52         //Create tables
53
54         $stage_one_queries = array(
55                 'CREATE TABLE Places(
56                 location_uri VARCHAR(255) unique,
57                 latitude FLOAT,
58                 longitude FLOAT,
59                 country CHAR(2))',
60
61                 'CREATE TABLE Countries (
62                 country varchar(2) PRIMARY KEY,
63                 country_name varchar(200),
64                 wikipedia_en varchar(120));',
65
66                 'CREATE TABLE Users (
67                 uniqueid SERIAL PRIMARY KEY,
68                 username VARCHAR(64) unique,
69                 password VARCHAR(32) NOT NULL,
70                 email VARCHAR(255),
71                 fullname VARCHAR(255),
72                 bio TEXT,
73                 homepage VARCHAR(255),
74                 location VARCHAR(255),
75                 userlevel INTEGER DEFAULT 0,
76                 anticommercial INTEGER DEFAULT 0,
77                 webid_uri VARCHAR(255),
78                 avatar_uri VARCHAR(255),
79                 openid_uri VARCHAR(100),
80                 active INTEGER DEFAULT 0,
81                 public_export INTEGER DEFAULT 0,
82                 location_uri VARCHAR(255) REFERENCES Places(location_uri),
83                 laconica_profile VARCHAR(255),
84                 created INTEGER DEFAULT 0,
85                 modified INTEGER DEFAULT 0,
86                 journal_rss VARCHAR(255),
87                 receive_emails INTEGER DEFAULT 1)',
88
89                 'CREATE TABLE Groups (
90                 id SERIAL PRIMARY KEY,
91                 groupname VARCHAR(64),
92                 owner INTEGER REFERENCES Users(uniqueid),
93                 fullname VARCHAR(255),
94                 bio TEXT,
95                 homepage VARCHAR(255),
96                 created INTEGER NOT NULL,
97                 modified INTEGER,
98                 avatar_uri VARCHAR(255),
99                 grouptype INTEGER)',
100
101                 'CREATE TABLE Group_Members (
102                 grp INTEGER REFERENCES Groups(id),
103                 member INTEGER REFERENCES Users(uniqueid),
104                 joined INTEGER NOT NULL,
105                 PRIMARY KEY (grp, member))',
106
107                 # TODO: REMOVE
108                 'CREATE TABLE AccountActivation(
109                 username VARCHAR(64),
110                 authcode VARCHAR(32),
111                 expires INTEGER)',
112
113                 'CREATE TABLE Auth (
114                 token VARCHAR(32) PRIMARY KEY,
115                 sk VARCHAR(32),
116                 expires INTEGER,
117                 username VARCHAR(64) REFERENCES Users(username))',
118
119                 'CREATE TABLE Artist(
120                 id SERIAL PRIMARY KEY,
121                 name VARCHAR(255) unique,
122                 mbid VARCHAR(36),
123                 imbid INTEGER,
124                 streamable INTEGER,
125                 bio_published INTEGER,
126                 bio_content TEXT,
127                 bio_summary TEXT,
128                 image_small VARCHAR(255),
129                 image_medium VARCHAR(255),
130                 image_large VARCHAR(255),
131                 homepage VARCHAR(255),
132                 hashtag VARCHAR(255),
133                 origin VARCHAR(255) REFERENCES Places(location_uri),
134                 flattr_uid VARCHAR(255))',
135
136                 'CREATE TABLE Album(
137                 id SERIAL PRIMARY KEY,
138                 name VARCHAR(255),
139                 artist_name VARCHAR(255) REFERENCES Artist(name),
140                 mbid VARCHAR(36),
141                 image VARCHAR(255),
142                 artwork_license VARCHAR(255),
143                 releasedate INTEGER,
144                 albumurl VARCHAR(255),
145                 downloadurl VARCHAR(255))',
146
147                 'CREATE TABLE Similar_Artist(
148                 name_a VARCHAR(255) REFERENCES Artist(name),
149                 name_b VARCHAR(255) REFERENCES Artist(name),
150                 PRIMARY KEY(name_a, name_b))'
151         );
152
153         $stage_two_queries_mysql = array(
154                 'CREATE TABLE Track(
155                 id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
156                 name VARCHAR(255),
157                 artist_name VARCHAR(255) REFERENCES Artist(name),
158                 album_name VARCHAR(255),
159                 mbid VARCHAR(36),
160                 duration INTEGER,
161                 streamable INTEGER DEFAULT 0,
162                 license VARCHAR(255),
163                 downloadurl VARCHAR(255),
164                 streamurl VARCHAR(255),
165                 otherid VARCHAR(16))'
166         );
167
168         $stage_two_queries_other = array(
169                 'CREATE SEQUENCE track_id_seq;',
170                 'CREATE TABLE Track(
171                 id INTEGER NOT NULL DEFAULT nextval(\'track_id_seq\'::regclass) PRIMARY KEY,
172                 name VARCHAR(255),
173                 artist_name VARCHAR(255) REFERENCES Artist(name),
174                 album_name VARCHAR(255),
175                 mbid VARCHAR(36),
176                 duration INTEGER,
177                 streamable INTEGER DEFAULT 0,
178                 license VARCHAR(255),
179                 downloadurl VARCHAR(255),
180                 streamurl VARCHAR(255),
181                 otherid VARCHAR(16))'
182         );
183
184         $stage_three_queries = array(
185                 'CREATE TABLE Scrobbles(
186                 userid INTEGER REFERENCES Users(uniqueid),
187                 track VARCHAR(255),
188                 album VARCHAR(255),
189                 artist VARCHAR(255) REFERENCES Artist(name),
190                 time INTEGER,
191                 mbid VARCHAR(36),
192                 source VARCHAR(6),
193                 rating CHAR(1),
194                 length INTEGER,
195                 stid INTEGER)',
196
197                 'CREATE TABLE Scrobble_Sessions(
198                 userid INTEGER REFERENCES Users(uniqueid),
199                 sessionid VARCHAR(32) PRIMARY KEY,
200                 client CHAR(3),
201                 api_key VARCHAR(32),
202                 expires INTEGER)',
203
204                 'CREATE TABLE Now_Playing(
205                 sessionid VARCHAR(32) PRIMARY KEY REFERENCES Scrobble_Sessions(sessionid) ON DELETE CASCADE,
206                 track VARCHAR(255),
207                 artist VARCHAR(255),
208                 album VARCHAR(255),
209                 mbid VARCHAR(36),
210                 expires INTEGER)',
211
212                 # TODO: Delete
213                 'CREATE TABLE Invitation_Request(
214                 email VARCHAR(255) PRIMARY KEY,
215                 time INTEGER)',
216
217                 'CREATE TABLE Invitations(
218                 inviter VARCHAR(64) REFERENCES Users(username),
219                 invitee VARCHAR(64) REFERENCES Users(username),
220                 code VARCHAR(32),
221                 PRIMARY KEY(inviter, invitee, code))',
222
223                 'CREATE TABLE ClientCodes(
224                 code CHAR(3),
225                 name VARCHAR(32),
226                 url VARCHAR(256),
227                 free CHAR(1),
228                 PRIMARY KEY(code))',
229
230                 'CREATE TABLE Tags(
231                 tag VARCHAR(64),
232                 artist VARCHAR(255) REFERENCES Artist(name),
233                 album VARCHAR(255),
234                 track VARCHAR(255),
235                 userid INTEGER REFERENCES Users(uniqueid),
236                 UNIQUE(tag, artist, album, track, userid))',
237
238                 'CREATE TABLE Manages(
239                 userid INTEGER REFERENCES Users(uniqueid),
240                 artist VARCHAR(255) REFERENCES Artist(name),
241                 authorised INTEGER)',
242
243                 'CREATE TABLE Error(
244                 id SERIAL PRIMARY KEY,
245                 msg TEXT,
246                 data TEXT,
247                 time INTEGER)',
248
249                 'CREATE TABLE Recovery_Request(
250                         username VARCHAR(64),
251                         email VARCHAR(255),
252                         code VARCHAR(32),
253                         expires INTEGER,
254                         PRIMARY KEY(username))',
255
256                 'CREATE TABLE Radio_Sessions(
257                         username VARCHAR(64),
258                         session VARCHAR(32),
259                         url VARCHAR(255),
260                         expires INTEGER NOT NULL DEFAULT 0,
261                         PRIMARY KEY(session))',
262
263                 //Table for delete profile requests
264                 'CREATE TABLE Delete_Request (
265                 code VARCHAR(300),
266                 expires INTEGER,
267                 username VARCHAR(64) REFERENCES Users(username),
268                 PRIMARY KEY(code))',
269
270                 'CREATE TABLE Scrobble_Track(
271                 id SERIAL PRIMARY KEY,
272                 artist VARCHAR(255) NOT NULL,
273                 album VARCHAR(255),
274                 name VARCHAR(255) NOT NULL,
275                 mbid VARCHAR(36),
276                 track INTEGER NOT NULL)',
277
278                 'CREATE VIEW Free_Scrobbles AS
279                 SELECT s.userid, s.track, s.artist, s.time, s.mbid, s.album, s.source, s.rating, s.length
280                 FROM Scrobbles s
281                 JOIN Scrobble_Track st ON s.stid = st.id
282                 JOIN Track t ON st.track = t.id
283                 WHERE t.streamable = 1',
284
285                 'CREATE TABLE Banned_Tracks (
286                 userid INTEGER REFERENCES Users(uniqueid) ON DELETE CASCADE,
287                 track varchar(255),
288                 artist varchar(255),
289                 time INTEGER,
290                 UNIQUE(userid, track, artist))',
291
292                 'CREATE TABLE Loved_Tracks (
293                 userid INTEGER REFERENCES Users(uniqueid) ON DELETE CASCADE,
294                 track varchar(255),
295                 artist varchar(255),
296                 time varchar(255),
297                 UNIQUE(userid, track, artist))',
298
299                 'CREATE TABLE Service_Connections (
300                 userid INTEGER REFERENCES Users(uniqueid) ON DELETE CASCADE,
301                 webservice_url VARCHAR(255),
302                 remote_key VARCHAR(255),
303                 remote_username VARCHAR(255),
304                 forward INTEGER DEFAULT 1)',
305
306                 'CREATE TABLE User_Relationships (
307                 uid1 INTEGER REFERENCES Users(uniqueid) ON DELETE CASCADE,
308                 uid2 INTEGER REFERENCES Users(uniqueid) ON DELETE CASCADE,
309                 established INTEGER NOT NULL,
310                 PRIMARY KEY (uid1, uid2))',
311
312                 'CREATE TABLE Relationship_Flags (
313                 flag VARCHAR(12),
314                 PRIMARY KEY (flag))',
315
316                 'CREATE TABLE User_Relationship_Flags (
317                 uid1 INTEGER,
318                 uid2 INTEGER,
319                 flag VARCHAR(12) REFERENCES Relationship_Flags(flag),
320                 PRIMARY KEY (uid1, uid2, flag),
321                 FOREIGN KEY (uid1, uid2) REFERENCES User_Relationships (uid1, uid2))',
322
323                 'INSERT INTO Relationship_Flags VALUES (\'contact\')',
324                 'INSERT INTO Relationship_Flags VALUES (\'acquaintance\')',
325                 'INSERT INTO Relationship_Flags VALUES (\'friend\')',
326                 'INSERT INTO Relationship_Flags VALUES (\'met\')',
327                 'INSERT INTO Relationship_Flags VALUES (\'co-worker\')',
328                 'INSERT INTO Relationship_Flags VALUES (\'colleague\')',
329                 'INSERT INTO Relationship_Flags VALUES (\'co-resident\')',
330                 'INSERT INTO Relationship_Flags VALUES (\'neighbor\')',
331                 'INSERT INTO Relationship_Flags VALUES (\'child\')',
332                 'INSERT INTO Relationship_Flags VALUES (\'parent\')',
333                 'INSERT INTO Relationship_Flags VALUES (\'sibling\')',
334                 'INSERT INTO Relationship_Flags VALUES (\'spouse\')',
335                 'INSERT INTO Relationship_Flags VALUES (\'kin\')',
336                 'INSERT INTO Relationship_Flags VALUES (\'muse\')',
337                 'INSERT INTO Relationship_Flags VALUES (\'crush\')',
338                 'INSERT INTO Relationship_Flags VALUES (\'date\')',
339                 'INSERT INTO Relationship_Flags VALUES (\'sweetheart\')',
340
341                 'CREATE TABLE User_Stats (
342                         userid INTEGER REFERENCES Users(uniqueid) ON DELETE CASCADE,
343                         scrobble_count INTEGER NOT NULL,
344                         PRIMARY KEY (userid))'
345         );
346
347         foreach ($stage_one_queries as $query) {
348                 try {
349                         $adodb->Execute($query);
350                 } catch (Exception $e) {
351                         die('Database Error: ' . $adodb->ErrorMsg());
352                 }
353         }
354
355         if (strtolower(substr($dbms, 0, 5)) == 'mysql') {
356                 foreach ($stage_two_queries_mysql as $query) {
357                         try {
358                                 $adodb->Execute($query);
359                         } catch (Exception $e) {
360                                 die('Database Error: ' . $adodb->ErrorMsg());
361                         }
362                 }
363         } else {
364                 foreach ($stage_two_queries_other as $query) {
365                         try {
366                                 $adodb->Execute($query);
367                         } catch (Exception $e) {
368                                 die('Database Error: ' . $adodb->ErrorMsg());
369                         }
370                 }
371         }
372
373         foreach ($stage_three_queries as $query) {
374                 try {
375                         $adodb->Execute($query);
376                 } catch (Exception $e) {
377                         die('Database Error: ' . $adodb->ErrorMsg());
378                 }
379         }
380
381         $adodb->Execute("CREATE INDEX scrobbles_time_idx ON Scrobbles(time)");
382         $adodb->Execute("CREATE INDEX scrobbles_userid_time_idx ON Scrobbles(userid, time)");
383         $adodb->Execute("CREATE INDEX scrobbles_track_idx on Scrobbles(track)");
384         $adodb->Execute("CREATE INDEX scrobble_track_name_idx ON Scrobble_Track(name)");
385         $adodb->Execute("CREATE INDEX track_streamable_idx on Track(streamable);");
386         $adodb->Execute("CREATE INDEX track_name_idx ON Track(name)");
387         $adodb->Execute("CREATE INDEX album_name_idx ON Album(name)");
388         $adodb->Execute("CREATE INDEX artist_name_idx ON Artist(name)");
389
390         if(strtolower(substr($dbms, 0, 5)) == 'pgsql') {
391                 // MySQL doesn't support the use of lower() to create case-insensitive indexes
392                 $adodb->Execute("CREATE INDEX album_lower_artistname_idx ON Album(lower(artist_name))");
393                 $adodb->Execute("CREATE INDEX track_lower_artist_idx ON Track(lower(artist_name))");
394                 $adodb->Execute("CREATE INDEX track_lower_name_idx ON Track(lower(name))");
395                 $adodb->Execute("CREATE INDEX scrobbles_lower_artist_idx on Scrobbles(lower(artist))");
396                 $adodb->Execute("CREATE INDEX scrobbles_lower_track_idx on Scrobbles(lower(track))");
397                 $adodb->Execute("CREATE INDEX groups_lower_groupname_idx ON Groups(lower(groupname))");
398
399                 // PostgreSQL stored functions
400                 $adodb->Execute("CREATE OR REPLACE LANGUAGE plpgsql;");
401                 $adodb->Execute("CREATE FUNCTION update_user_stats_scrobble_count() RETURNS TRIGGER AS $$
402                         DECLARE s_count int;
403                         BEGIN
404                                 UPDATE User_Stats SET scrobble_count = scrobble_count + 1 WHERE userid = NEW.userid;
405                                 IF found THEN
406                                         RETURN NULL;
407                                 END IF;
408                                 BEGIN
409                                         -- userid not in User_Stats table, get current scrobble count from Scrobbles
410                                         -- and insert userid into User_Stats
411                                         SELECT COUNT(userid) into s_count FROM Scrobbles WHERE userid = NEW.userid;
412                                         INSERT INTO User_Stats(userid, scrobble_count) VALUES(NEW.userid, s_count);
413                                         RETURN NULL;
414                                 END;
415                         END;
416                         $$ LANGUAGE plpgsql;");
417                 $adodb->Execute("CREATE TRIGGER update_user_stats_scrobble_count
418                         AFTER INSERT ON Scrobbles
419                         FOR EACH ROW EXECUTE PROCEDURE update_user_stats_scrobble_count();");
420
421         } elseif (substr($dbms, 0, 5) == 'mysql') {
422                 $adodb->Execute("CREATE PROCEDURE update_user_stats_scrobble_count(uid INT)
423                         main: BEGIN
424                                 DECLARE s_count INT;
425                                 UPDATE User_Stats SET scrobble_count = (scrobble_count + 1) WHERE userid = uid;
426                                 IF ROW_COUNT() > 0 THEN
427                                         LEAVE main;
428                                 END IF;
429                                 SELECT COUNT(userid) INTO s_count FROM Scrobbles WHERE userid = uid;
430                                 INSERT INTO User_Stats(userid, scrobble_count) VALUES(uid, s_count);
431                         END main;");
432                 $adodb->Execute("CREATE TRIGGER update_user_stats_scrobble_count
433                         AFTER INSERT ON Scrobbles
434                         FOR EACH ROW CALL update_user_stats_scrobble_count(NEW.userid);");
435         }
436
437         $adodb->Close();
438
439         $submissions_server = $_POST['submissions'];
440         $install_path = dirname(__FILE__) . '/';
441
442         //Write out the configuration
443         $config = "<?php\n \$config_version = " . $version .";\n \$connect_string = '" . $connect_string . "';\n \$submissions_server = '" . $submissions_server . "';\n \$install_path = '" . $install_path . "';\n \$adodb_connect_string = '" . $adodb_connect_string . "'; ";
444
445         $conf_file = fopen('config.php', 'w');
446         $result = fwrite($conf_file, $config);
447         fclose($conf_file);
448
449         if (!$result) {
450                 $print_config = str_replace('<', '&lt;', $config);
451                 die('Unable to write to file \'<i>config.php</i>\'. Please create this file and copy the following in to it: <br /><pre>' . $print_config . '</pre>');
452         }
453
454         die('Configuration completed successfully!');
455 }
456
457 ?>
458 <html>
459         <head>
460                 <title>GNUkebox Installer</title>
461                 <script type='text/javascript'>
462                         function showSqlite() {
463                                 document.getElementById("sqlite").style.visibility = "visible";
464                                 document.getElementById("networkdbms").style.visibility = "hidden";
465                         }
466
467                         function showNetworkDBMS() {
468                                 document.getElementById("sqlite").style.visibility = "hidden";
469                                 document.getElementById("networkdbms").style.visibility = "visible";
470                         }
471                 </script>
472         </head>
473
474         <body onload="showSqlite()">
475                 <h1>GNUkebox Installer</h1>
476                 <form method="post">
477                         <h2>Database</h2>
478                         Database Management System: <br />
479                         <input type="radio" name="dbms" value="sqlite" onclick='showSqlite()' checked>SQLite (use an absolute path)</input><br />
480                         <input type="radio" name="dbms" value="mysql" onclick='showNetworkDBMS()'>MySQL</input><br />
481                         <input type="radio" name="dbms" value="pgsql" onclick='showNetworkDBMS()'>PostgreSQL</input><br />
482                         <br />
483                         <div id="sqlite">
484                                 Filename: <input type="text" name="filename" /><br />
485                         </div>
486                         <div id="networkdbms">
487                                 Hostname: <input type="text" name="hostname" /><br />
488                                 Port: <input type="text" name="port" /><br />
489                                 Database: <input type="text" name="dbname" /><br />
490                                 Username: <input type="text" name="username" /><br />
491                                 Password: <input type="password" name="password" /><br />
492                         </div>
493                         <br />
494                         <h2>Servers</h2>
495                         Submissions Server URL: <input type="text" name="submissions" value="<?php echo getAbsoluteURL(); ?>" /><br />
496                         <br />
497                         <input type="submit" value="Install" name="install" />
498                 </form>
499                 <br />
500                 <div align="center"><a href="http://docs.jurg.no/gnufm_install.txt">Help</a></div>
501         </body>
502 </html>
503
504