Browse Source

Basic Typica user functionality complete. Fixes #108. Fixes #109.

Neal Wilson 6 years ago
parent
commit
6e4c236804
3 changed files with 230 additions and 3 deletions
  1. 19
    0
      config/Windows/navigation.xml
  2. 12
    1
      src/typica.w
  3. 199
    2
      src/user.w

+ 19
- 0
config/Windows/navigation.xml View File

@@ -73,6 +73,10 @@
73 73
     <menu name="Database">
74 74
         <item id="resetconnection">Forget Connection Details</item>
75 75
     </menu>
76
+	<menu name="Users">
77
+		<item id="switchuser">Switch User</item>
78
+		<item id="createuser">Create New Users</item>
79
+	</menu>
76 80
     <program>
77 81
         var window = this;
78 82
         var navigationwindow = window;
@@ -376,8 +380,23 @@
376 380
 				var newUserDialog = new NewTypicaUser();
377 381
 				newUserDialog.exec();
378 382
 			}
383
+			if(!Application.autoLogin()) {
384
+				var loginDialog = new LoginDialog();
385
+				loginDialog.exec();
386
+			}
379 387
 			query = query.invalidate();
380 388
 		}
389
+		
390
+		var switchuser = findChildObject(this, 'switchuser');
391
+		switchuser.triggered.connect(function() {
392
+			var loginDialog = new LoginDialog();
393
+			loginDialog.exec();
394
+		});
395
+		var createuser = findChildObject(this, 'createuser');
396
+		createuser.triggered.connect(function() {
397
+			var newUserDialog = new NewTypicaUser();
398
+			newUserDialog.exec();
399
+		});
381 400
         ]]>
382 401
     </program>
383 402
 </window>

+ 12
- 1
src/typica.w View File

@@ -1083,6 +1083,10 @@ ScriptQMainWindow::ScriptQMainWindow()@+: QMainWindow(NULL),
1083 1083
     {
1084 1084
 	    statusBar()->addWidget(new QLabel(tr("Not connected to database")));
1085 1085
     }
1086
+    else
1087
+    {
1088
+	    statusBar()->addWidget(new UserLabel);
1089
+    }
1086 1090
 }
1087 1091
 
1088 1092
 void ScriptQMainWindow::saveSizeAndPosition(const QString &key)
@@ -12826,14 +12830,21 @@ class Application : public QApplication@/
12826 12830
         @<Device configuration members@>@;
12827 12831
         QSqlDatabase database();
12828 12832
         Q_INVOKABLE bool databaseConnected();
12833
+        Q_INVOKABLE QString currentTypicaUser();
12834
+        Q_INVOKABLE bool login(const QString &user, const QString &password);
12835
+        Q_INVOKABLE bool autoLogin();
12829 12836
         QScriptEngine *engine;@/
12830 12837
     @[public slots@]:@/
12831 12838
 	    void setDatabaseConnected(bool status);
12839
+	    void setCurrentTypicaUser(const QString &user);
12832 12840
         @<Extended Application slots@>@;
12841
+    @[signals@]:@/
12842
+	    void userChanged(const QString &user);
12833 12843
     private:@/
12834 12844
         @<Application private data members@>@;
12835 12845
         QDomDocument conf;
12836 12846
         bool connectionStatus;
12847
+        QString currentUser;
12837 12848
 };
12838 12849
 
12839 12850
 @ The constructor for this class handles a few things that had previously been
@@ -12841,7 +12852,7 @@ handled in |main()|.
12841 12852
 
12842 12853
 @<Application Implementation@>=
12843 12854
 Application::Application(int &argc, char **argv) : QApplication(argc, argv),
12844
-	connectionStatus(false)@/
12855
+	connectionStatus(false), currentUser(QString())@/
12845 12856
 {
12846 12857
     @<Allow use of the default QSettings constructor@>@;
12847 12858
     @<Load translation objects@>@;

+ 199
- 2
src/user.w View File

@@ -5,6 +5,201 @@ are separated. This means that there must be controls for creating new users
5 5
 and for selecting the user to log in as. Other management interfaces can be
6 6
 implemented in configuration scripts.
7 7
 
8
+@* Application extensions for user handling.
9
+
10
+\noindent In order to present information about the currently logged in user
11
+globally, it was decided to provide a few methods in |Application| that can be
12
+used to report and change the current user.
13
+
14
+The first of these simply reports the currently logged in user.
15
+
16
+@<Application Implementation@>=
17
+QString Application::currentTypicaUser()
18
+{
19
+	return currentUser;
20
+}
21
+
22
+@ Next is a method that can be used to force the login of a specified user
23
+without checking for an entered password. This is used for users that are set
24
+to login automatically.
25
+
26
+@<Application Implementation@>=
27
+void Application::setCurrentTypicaUser(const QString &user)
28
+{
29
+	currentUser = user;
30
+	emit userChanged(currentUser);
31
+}
32
+
33
+@ A login method is provided which determines if a user exists that matches the
34
+user name and password specified and reports if the login attempt was
35
+successful.
36
+
37
+@<Application Implementation@>=
38
+bool Application::login(const QString &user, const QString &password)
39
+{
40
+	SqlQueryConnection h;
41
+	QSqlQuery *dbquery = h.operator->();
42
+	dbquery->prepare("SELECT 1 FROM typica_users WHERE name = :name AND password = :password AND active = TRUE");
43
+	dbquery->bindValue(":name", user);
44
+	dbquery->bindValue(":password", password);
45
+	dbquery->exec();
46
+	if(dbquery->next())
47
+	{
48
+		currentUser = user;
49
+		emit userChanged(currentUser);
50
+		return true;
51
+	}
52
+	return false;
53
+}
54
+
55
+@ A convenience method is also provided to attempt an automatic login if one is
56
+specified in the database.
57
+
58
+@<Application Implementation@>=
59
+bool Application::autoLogin()
60
+{
61
+	SqlQueryConnection h;
62
+	QSqlQuery *dbquery = h.operator->();
63
+	dbquery->exec("SELECT name FROM typica_users WHERE auto_login = TRUE");
64
+	if(dbquery->next())
65
+	{
66
+		currentUser = dbquery->value(0).toString();
67
+		emit userChanged(currentUser);
68
+		return true;
69
+	}
70
+	return false;
71
+}
72
+
73
+@* Login dialog.
74
+
75
+\noindent If there are no users set to log in automatically or any time a user
76
+change is requested, a login dialog should be presented.
77
+
78
+@<Class declarations@>=
79
+class LoginDialog : public QDialog
80
+{
81
+	Q_OBJECT
82
+	public:
83
+		LoginDialog();
84
+	public slots:
85
+		void attemptLogin();
86
+	private:
87
+		QLineEdit *user;
88
+		QLineEdit *password;
89
+		QLabel *warning;
90
+		QPushButton *login;
91
+};
92
+
93
+@ The constructor sets up the interface.
94
+
95
+@<LoginDialog implementation@>=
96
+LoginDialog::LoginDialog() : QDialog(),
97
+	user(new QLineEdit), password(new QLineEdit),
98
+	warning(new QLabel(tr("Log in failed."))),
99
+	login(new QPushButton(tr("Log In")))
100
+{
101
+	setModal(true);
102
+	QVBoxLayout *mainLayout = new QVBoxLayout;
103
+	warning->setVisible(false);
104
+	password->setEchoMode(QLineEdit::Password);
105
+	QFormLayout *form = new QFormLayout;
106
+	form->addRow(tr("Name:"), user);
107
+	form->addRow(tr("Password:"), password);
108
+	form->addRow(warning);
109
+	QHBoxLayout *buttonBox = new QHBoxLayout;
110
+	buttonBox->addStretch();
111
+	buttonBox->addWidget(login);
112
+	mainLayout->addLayout(form);
113
+	mainLayout->addLayout(buttonBox);
114
+	connect(login, SIGNAL(clicked()), this, SLOT(attemptLogin()));
115
+	setLayout(mainLayout);
116
+}
117
+
118
+@ The log in button attempts to log in with the specified credentials.
119
+
120
+@<LoginDialog implementation@>=
121
+void LoginDialog::attemptLogin()
122
+{
123
+	if(AppInstance->login(user->text(), password->text()))
124
+	{
125
+		accept();
126
+	}
127
+	else
128
+	{
129
+		warning->setVisible(true);
130
+	}
131
+}
132
+
133
+@ Scripts must be able to create login dialogs.
134
+
135
+@<Set up the scripting engine@>=
136
+constructor = engine->newFunction(constructLoginDialog);
137
+value = engine->newQMetaObject(&LoginDialog::staticMetaObject, constructor);
138
+engine->globalObject().setProperty("LoginDialog", value);
139
+
140
+@ The constructor is trivial.
141
+
142
+@<Functions for scripting@>=
143
+QScriptValue constructLoginDialog(QScriptContext *, QScriptEngine *engine)
144
+{
145
+	QScriptValue object = engine->newQObject(new LoginDialog);
146
+	return object;
147
+}
148
+
149
+@ A function prototype is required.
150
+
151
+@<Function prototypes for scripting@>=
152
+QScriptValue constructLoginDialog(QScriptContext *context, QScriptEngine *engine);
153
+
154
+@* Currently logged in user.
155
+
156
+\noindent Every main window in \pn{} should be able to report on the currently
157
+logged in user and it should be possible to bring up an interface to switch
158
+users. An easy way to do this is through a widget inserted into the status bar
159
+of every window that listens for user change data from the |Application|
160
+instance.
161
+
162
+@<Class declarations@>=
163
+class UserLabel : public QLabel
164
+{
165
+	Q_OBJECT
166
+	public:
167
+		UserLabel();
168
+	public slots:
169
+		void updateLabel(const QString &user);
170
+	protected:
171
+		void mouseReleaseEvent(QMouseEvent *event);
172
+};
173
+
174
+@ On first instantiation, the constructor sets the displayed text to indicate
175
+the currently logged in user and starts listening for user change events.
176
+
177
+@<UserLabel implementation@>=
178
+UserLabel::UserLabel() : QLabel()
179
+{
180
+	setTextFormat(Qt::PlainText);
181
+	updateLabel(AppInstance->currentTypicaUser());
182
+	connect(AppInstance, SIGNAL(userChanged(QString)),
183
+	        this, SLOT(updateLabel(QString)));
184
+}
185
+
186
+@ When the currently logged in user changes, the label text updates itself.
187
+
188
+@<UserLabel implementation@>=
189
+void UserLabel::updateLabel(const QString &user)
190
+{
191
+	setText(QString(tr("Current operator: %1").arg(user)));
192
+}
193
+
194
+@ In order to handle clicks, |mouseReleaseEvent()| is implemented.
195
+
196
+@<UserLabel implementation@>=
197
+void UserLabel::mouseReleaseEvent(QMouseEvent *event)
198
+{
199
+	LoginDialog *dialog = new LoginDialog;
200
+	dialog->exec();
201
+}
202
+
8 203
 @* User Creation.
9 204
 
10 205
 \noindent The first time \pn{} is started with a database connection and a
@@ -144,7 +339,9 @@ QScriptValue constructNewTypicaUser(QScriptContext *, QScriptEngine *engine)
144 339
 @<Function prototypes for scripting@>=
145 340
 QScriptValue constructNewTypicaUser(QScriptContext *context, QScriptEngine *engine);
146 341
 
147
-@ Add class implementation to generated source file.
342
+@ Add class implementations to generated source file.
148 343
 
149 344
 @<Class implementations@>=
150
-@<NewTypicaUser implementation@>
345
+@<NewTypicaUser implementation@>
346
+@<UserLabel implementation@>
347
+@<LoginDialog implementation@>

Loading…
Cancel
Save