Removing explicit mentions to users in the cokebank
[tpg/opendispense2.git] / src / cokebank_sqlite / main.c
1 /*
2  * OpenDispense 2 
3  * UCC (University [of WA] Computer Club) Electronic Accounting System
4  *
5  * SQLite Coke Bank (Accounts Database)
6  *
7  * This file is licenced under the 3-clause BSD Licence. See the file
8  * COPYING for full details.
9  */
10 #include "../cokebank.h"
11 #include <sqlite3.h>
12
13 const char * const csBank_CreateAccountQry = "CREATE TABLE IF NOT EXISTS accounts ("
14 "       acct_id INTEGER PRIMARY KEY NOT NULL,"
15 "       acct_balance INTEGER NOT NULL,"
16 "       acct_name STRING UNIQUE,"
17 "       acct_uid INTEGER UNIQUE,"
18 "       acct_pin INTEGER CHECK (acct_pin > 0 AND acct_pin < 10000),"
19 "       acct_is_disabled BOOLEAN NOT NULL DEFAULT false,"
20 "       acct_is_coke BOOLEAN NOT NULL DEFAULT false,"
21 "       acct_is_wheel BOOLEAN NOT NULL DEFAULT false,"
22 "       acct_is_door BOOLEAN NOT NULL DEFAULT false,"
23 "       acct_is_internal BOOLEAN NOT NULL DEFAULT false"
24 ")";
25 const char * const csBank_CreateCardsQry = "CREATE TABLE IF NOT EXISTS cards ("
26 "       acct_id INTEGER NOT NULL,"
27 "       card_name STRING NOT NULL UNIQUE,"
28 "       FOREIGN KEY (acct_id) REFERENCES accounts (acct_id) ON DELETE CASCADE"
29 //                       Deletion of the account frees the card  ^ ^ ^
30 ")";
31
32 // === PROTOYPES ===
33  int    Bank_Initialise(const char *Argument);
34  int    Bank_Transfer(int SourceAcct, int DestAcct, int Ammount, const char *Reason);
35  int    Bank_GetUserFlags(int AcctID);
36  int    Bank_SetUserFlags(int AcctID, int Mask, int Value);
37  int    Bank_GetBalance(int AcctID);
38 char    *Bank_GetAcctName(int AcctID);
39 sqlite3_stmt    *Bank_int_MakeStatemnt(sqlite3 *Database, const char *Query);
40 sqlite3_stmt    *Bank_int_QuerySingle(sqlite3 *Database, const char *Query);
41
42 // === GLOBALS ===
43 sqlite3 *gBank_Database;
44
45 // === CODE ===
46 int Bank_Initialise(const char *Argument)
47 {
48          int    rv;
49         char    *errmsg;
50         // Open database
51         rv = sqlite3_open(Argument, &gBank_Database);
52         if(rv != 0)
53         {
54                 fprintf(stderr, "CokeBank: Unable to open database '%s'\n", Argument);
55                 fprintf(stderr, "Reason: %s\n", sqlite3_errmsg(gBank_Database));
56                 sqlite3_close(gBank_Database);
57                 return 1;
58         }
59
60         // Check structure
61         rv = sqlite3_exec(gBank_Database, "SELECT acct_id FROM accounts LIMIT 1", NULL, NULL, &errmsg);
62         if( rv == SQLITE_OK )
63         {
64                 // NOP
65         }
66         else if( rv == SQLITE_NOTFOUND )
67         {
68                 sqlite3_free(errmsg);
69                 // Create tables
70                 // - Accounts
71                 rv = sqlite3_exec(gBank_Database, csBank_CreateAccountQry, NULL, NULL, &errmsg);
72                 if( rv != SQLITE_OK ) {
73                         fprintf(stderr, "SQLite Error: %s\n", errmsg);
74                         sqlite3_free(errmsg);
75                         return 1;
76                 }
77                 // - Mifare relation
78                 rv = sqlite3_exec(gBank_Database, csBank_CreateCardsQry, NULL, NULL, &errmsg);
79                 if( rv != SQLITE_OK ) {
80                         fprintf(stderr, "SQLite Error: %s\n", errmsg);
81                         sqlite3_free(errmsg);
82                         return 1;
83                 }
84         }
85         else
86         {
87                 // Unknown error
88                 fprintf(stderr, "SQLite Error: %s\n", errmsg);
89                 sqlite3_free(errmsg);
90                 return 1;
91         }
92
93         return 0;
94 }
95
96 /*
97  * Move Money
98  */
99 int Bank_Transfer(int SourceUser, int DestUser, int Ammount, const char *Reason)
100 {
101         char    *query
102          int    rv;
103         char    *errmsg;
104         
105         // Begin SQL Transaction
106         sqlite3_exec(gBank_Database, "BEGIN TRANSACTION", NULL, NULL, NULL);
107
108         // Take from the source
109         query = mkstr("UPDATE accounts SET acct_balance=acct_balance-%i WHERE acct_id=%i", Ammount, SourceUser);
110         rv = sqlite3_exec(gBank_Database, query, NULL, NULL, &errmsg);
111         free(query);
112         if( rv != SQLITE_OK )
113         {
114                 fprintf(stderr, "SQLite Error: %s\n", errmsg);
115                 sqlite3_free(errMsg);
116                 sqlite3_query(gBank_Database, "ROLLBACK", NULL, NULL, NULL);
117                 return 1;
118         }
119
120         // Give to the destination
121         query = mkstr("UPDATE accounts SET acct_balance=acct_balance+%i WHERE acct_id=%i", Ammount, DestUser);
122         rv = sqlite3_exec(gBank_Database, query, NULL, NULL, &errmsg);
123         free(query);
124         if( rv != SQLITE_OK )
125         {
126                 fprintf(stderr, "SQLite Error: %s\n", errmsg);
127                 sqlite3_free(errmsg);
128                 sqlite3_query(gBank_Database, "ROLLBACK", NULL, NULL, NULL);
129                 return 1;
130         }
131
132         // Commit transaction
133         sqlite3_query(gBank_Database, "COMMIT", NULL, NULL, NULL);
134
135         return 0;
136 }
137
138 /*
139  * Get user flags
140  */
141 int Bank_GetUserFlags(int UserID)
142 {
143         sqlite3_stmt    *statement;
144         char    *query;
145          int    rv;
146          int    ret;
147
148         // Build Query
149         query = mkstr(
150                 "SELECT acct_is_disabled,acct_is_coke,acct_is_wheel,acct_is_door,acct_is_internal"
151                 " FROM accounts WHERE acct_id=%i LIMIT 1",
152                 UserID
153                 );
154         statement = Bank_int_QuerySingle(gBank_Database, query);
155         free(query);
156         if( !statement )        return -1;
157
158         // Get Flags
159         ret = 0;
160         // - Disabled
161         if( sqlite3_column_int(statement, 0) )  ret |= USER_FLAG_DISABLED;
162         // - Coke
163         if( sqlite3_column_int(statement, 1) )  ret |= USER_FLAG_COKE;
164         // - Wheel
165         if( sqlite3_column_int(statement, 2) )  ret |= USER_FLAG_WHEEL;
166         // - Door
167         if( sqlite3_column_int(statement, 3) )  ret |= USER_FLAG_DOOR;
168         // - Internal
169         if( sqlite3_column_int(statement, 3) )  ret |= USER_FLAG_INTERNAL;
170         
171         // Destroy and return
172         sqlite3_finalise(statement);
173         
174         return ret;
175 }
176
177 /*
178  * Set user flags
179  */
180 int Bank_SetUserFlags(int UserID, int Mask, int Value)
181 {
182         char    *query;
183          int    rv;
184         char    *errmsg;
185
186         #define MAP_FLAG(name, flag)    (Mask&(flag)?(Value&(flag)?","name"=1":","name"=0"))
187         query = mkstr(
188                 "UDPATE accounts WHERE acct_id=%i SET acct_id=acct_id%s%s%s%s%s",
189                 MAP_FLAG("acct_is_coke", USER_FLAG_COKE),
190                 MAP_FLAG("acct_is_wheel", USER_FLAG_WHEEL),
191                 MAP_FLAG("acct_is_door", USER_FLAG_DOORGROUP),
192                 MAP_FLAG("acct_is_internal", USER_FLAG_INTERNAL),
193                 MAP_FLAG("acct_is_disabled", USER_FLAG_DISABLED)
194                 );
195         #undef MAP_FLAG
196
197         // Execute Query
198         rv = sqlite3_query(gBank_Database, query, NULL, NULL, &errmsg);
199         free(query);
200         if( rv != SQLITE_OK )
201         {
202                 fprintf(stderr, "SQLite Error: %s\n", errmsg);
203                 sqlite3_free(errmsg);
204                 return -1;
205         }
206         
207         return 0;
208 }
209
210 /*
211  * Get user balance
212  */
213 int Bank_GetBalance(int AcctID)
214 {
215         sqlite3_stmt    *statement;
216         char    *query;
217          int    ret;
218         
219         query = mkstr("SELECT acct_balance FROM accounts WHERE acct_id=%i LIMIT 1", AcctID);
220         statement = Bank_int_QuerySingle(gBank_Database, query);
221         free(query);
222         if( !statement )        return INT_MIN;
223         
224         // Read return value
225         ret = sqlite3_column_int(statement, 0);
226         
227         // Clean up and return
228         sqlite3_finalise(statement);
229         return ret;
230 }
231
232 /*
233  * Get the name of an account
234  */
235 char *Bank_GetUserName(int AcctID)
236 {
237         sqlite3_stmt    *statement;
238         char    *query;
239         char    *ret;
240         
241         query = mkstr("SELECT acct_name FROM accounts WHERE acct_id=%i LIMIT 1", AcctID);
242         statement = Bank_int_QuerySingle(gBank_Database, query);
243         free(query);
244         if( !statement )        return NULL;
245         
246         // Read return value
247         ret = strdup( sqlite3_column_text(statement, 0) );
248         
249         // Clean up and return
250         sqlite3_finalise(statement);
251         return ret;
252 }
253
254 /*
255  * Create a SQLite Statement
256  */
257 sqlite3_stmt *Bank_int_MakeStatemnt(sqlite3 *Database, const char *Query)
258 {
259          int    rv;
260         sqlite3_stmt    *ret;
261         rv = sqlite3_prepare_v2(Database, Query, strlen(Query)+1, &ret, NULL);
262         free(query);
263         if( rv != SQLITE_OK ) {
264                 fprintf(stderr, "SQLite Error: %s\n", sqlite3_errmsg(Database));
265                 fprintf(stderr, "query = \"%s\"\n", Query);
266                 return NULL;
267         }
268         
269         return ret;
270 }
271
272 /*
273  * Create a SQLite statement and query it for the first row
274  * Returns NULL if the the set is empty
275  */
276 sqlite3_stmt *Bank_int_QuerySingle(sqlite3 *Database, const char *Query)
277 {
278         sqlite3_stmt    *ret;
279          int    rv;
280         
281         // Prepare query
282         ret = Bank_int_MakeStatemnt(Database, Query);
283         if( !statement )        return NULL;
284         
285         // Get row
286         rv = sqlite3_step(statement);
287         // - Empty result set
288         if( rv == SQLITE_DONE ) return NULL;
289         // - Other error
290         if( rv != SQLITE_ROW ) {
291                 fprintf(stderr, "SQLite Error: %s\n", sqlite3_errmsg(gBank_Database));
292                 fprintf(stderr, "query = \"%s\"\n", Query);
293                 return NULL;
294         }
295         
296         return ret;
297 }

UCC git Repository :: git.ucc.asn.au