[Pharo] Personal fitness tracker web app.
Got login to work (?)
Changed files
- src/MyFitnessTracker/MFTLearnTab.class.st
- src/MyFitnessTracker/MFTLoginRegisterLogoutComponent.class.st
- src/MyFitnessTracker/MFTPage.class.st
- src/MyFitnessTracker/MFTProfileTab.class.st
- src/MyFitnessTracker/MFTPublicHomepageTab.class.st
- src/MyFitnessTracker/MFTSQLite3Database.class.st
- src/MyFitnessTracker/MFTSession.class.st
- src/MyFitnessTracker/MFTTab.class.st
- src/MyFitnessTracker/MFTUser.class.st
- src/MyFitnessTracker/MFTUserHomepageTab.class.st
- src/MyFitnessTracker/MFTWeightsListTab.class.st
- src/MyFitnessTracker/MFTWorkoutsListTab.class.st
src/MyFitnessTracker/MFTLearnTab.class.st
@@ -1,6 +1,6 @@
1
1
Class {
2
2
#name : #MFTLearnTab,
3
Removed:
#superclass : #MFTTab,
3
Added:
#superclass : #MFTPage,
4
4
#instVars : [
5
5
'articles'
6
6
],
src/MyFitnessTracker/MFTLoginRegisterLogoutComponent.class.st
@@ -15,17 +15,17 @@
15
15
If no matching user is found, kill the connection."
16
16
17
17
| connection existingUser passwordHash |
18
Removed:
connection := (MFTSQLite3Database openOn:
19
Removed:
(Smalltalk imageDirectory / 'mft.sqlite3') fullName)
20
Removed:
connection.
18
Added:
connection := MFTSQLite3Database defaultConnection.
19
Added:
connection open.
21
20
existingUser := ((connection
22
21
execute: 'SELECT * FROM users WHERE username = ?'
23
22
value: aMFTUser username) onlyRow: [
24
23
Dictionary new ]) asDictionary.
24
Added:
connection close.
25
25
passwordHash := existingUser
26
26
at: #password_hash
27
27
ifAbsent: [ String empty ].
28
Removed:
connection close.
28
Added:
29
29
aMFTUser passwordHash = passwordHash
30
30
ifTrue: [ self login: (MFTUser newFromDictionary: existingUser) ]
31
31
ifFalse: [ "TODO: user should be prompted to retry logging in."
@@ -42,22 +42,13 @@
42
42
{ #category : #login }
43
43
MFTLoginRegisterLogoutComponent >> login: aMFTUser [
44
44
45
Removed:
| connection loginDateAndTime |
45
Added:
| db |
46
Added:
db := MFTSQLite3Database newFromDefault.
47
Added:
db connection open.
48
Added:
self session db: db.
49
Added:
self session db updateLoginDateAndTime: aMFTUser.
46
50
self session user: aMFTUser.
47
51
self session user isLoggedIn: true.
48
Removed:
49
Removed:
loginDateAndTime := DateAndTime now asUTC rounded.
50
Removed:
user lastConnectionDateTime: loginDateAndTime.
51
Removed:
connection := (MFTSQLite3Database openOn:
52
Removed:
(Smalltalk imageDirectory / 'mft.sqlite3') fullName)
53
Removed:
connection.
54
Removed:
connection
55
Removed:
execute: 'UPDATE users
56
Removed:
SET last_connection_date_time = ?
57
Removed:
WHERE username = ?'
58
Removed:
value: loginDateAndTime
59
Removed:
value: aMFTUser username.
60
Removed:
connection close.
61
52
self session mainPages at: 1 put: MFTUserHomepageTab new
62
53
]
63
54
@@ -67,20 +58,6 @@
67
58
self session unregistered
68
59
]
69
60
70
Removed:
{ #category : #'as yet unclassified' }
71
Removed:
MFTLoginRegisterLogoutComponent >> registerNewUser: aMFTUser [
72
Removed:
73
Removed:
| connection |
74
Removed:
connection := (MFTSQLite3Database openOn:
75
Removed:
(Smalltalk imageDirectory / 'mft.sqlite3') fullName)
76
Removed:
connection.
77
Removed:
connection
78
Removed:
execute: 'INSERT INTO users(username,password_hash) VALUES (?, ?);'
79
Removed:
value: aMFTUser username
80
Removed:
value: aMFTUser passwordHash.
81
Removed:
connection close
82
Removed:
]
83
Removed:
84
61
{ #category : #rendering }
85
62
MFTLoginRegisterLogoutComponent >> renderContentOn: html [
86
63
@@ -192,6 +169,6 @@
192
169
with: 'Cancel'.
193
170
html formButton
194
171
bePrimary;
195
Removed:
callback: [ self registerNewUser: user ];
172
Added:
callback: [ MFTSQLite3Database registerNewUser: user ];
196
173
with: 'Register' ] ] ] ] ]
197
174
]
src/MyFitnessTracker/MFTPage.class.st
@@ -0,0 +1,14 @@
1
Added:
Class {
2
Added:
#name : #MFTPage,
3
Added:
#superclass : #SBSComponent,
4
Added:
#instVars : [
5
Added:
'title'
6
Added:
],
7
Added:
#category : #'MyFitnessTracker-Components'
8
Added:
}
9
Added:
10
Added:
{ #category : #accessing }
11
Added:
MFTPage >> title [
12
Added:
13
Added:
^ title asString
14
Added:
]
src/MyFitnessTracker/MFTProfileTab.class.st
@@ -1,6 +1,6 @@
1
1
Class {
2
2
#name : #MFTProfileTab,
3
Removed:
#superclass : #MFTTab,
3
Added:
#superclass : #MFTPage,
4
4
#category : #'MyFitnessTracker-Components'
5
5
}
6
6
src/MyFitnessTracker/MFTPublicHomepageTab.class.st
@@ -1,6 +1,6 @@
1
1
Class {
2
2
#name : #MFTPublicHomepageTab,
3
Removed:
#superclass : #MFTTab,
3
Added:
#superclass : #MFTPage,
4
4
#category : #'MyFitnessTracker-Components'
5
5
}
6
6
@@ -22,9 +22,6 @@
22
22
{ #category : #rendering }
23
23
MFTPublicHomepageTab >> renderMainCardOn: html [
24
24
25
Removed:
self session user isLoggedIn ifTrue: [
26
Removed:
(self session db select: '*' from: 'users') do: [ :each |
27
Removed:
html listItem: each asArray ] ].
28
25
html card: [
29
26
html jumbotron
30
27
class: 'p-3 bg-light';
@@ -33,15 +30,13 @@
33
30
level: 1;
34
31
with: 'Welcome to My Fitness Tracker!'.
35
32
html big textMuted with: 'Free Software never looked so fit.'.
36
Removed:
html paragraph: (self session user isLoggedIn
37
Removed:
ifTrue: [ 'User ' , self session user , ' is logged in.' ]
38
Removed:
ifFalse: [ 'No user is currently logged in.' ]).
39
33
html form: [ "TODO"
40
34
html formButton
41
35
bePrimary;
42
36
beLarge;
43
37
class: 'mt-3';
44
Removed:
callback: [ self call: MFTWorkoutDialog ];
38
Added:
callback: [
39
Added:
self session activePage: (self session mainPages at: 2) ];
45
40
with: 'Log a workout' ] ] ]
46
41
]
47
42
src/MyFitnessTracker/MFTSQLite3Database.class.st
@@ -1,46 +1,88 @@
1
1
Class {
2
2
#name : #MFTSQLite3Database,
3
3
#superclass : #SQLite3Database,
4
Added:
#classInstVars : [
5
Added:
'defaultLocation'
6
Added:
],
4
7
#category : #'MyFitnessTracker-Model'
5
8
}
6
9
7
10
{ #category : #'as yet unclassified' }
8
Removed:
MFTSQLite3Database class >> ensureTablesExist [
11
Added:
MFTSQLite3Database class >> defaultConnection [
9
12
10
Removed:
| aMFTDatabase |
11
Removed:
aMFTDatabase := self new.
13
Added:
^ self newFromDefault connection
14
Added:
]
12
15
13
Removed:
aMFTDatabase connection execute:
14
Removed:
'CREATE TABLE IF NOT EXISTS "prospects" (
16
Added:
{ #category : #accessing }
17
Added:
MFTSQLite3Database class >> defaultLocation [
18
Added:
19
Added:
^ defaultLocation
20
Added:
]
21
Added:
22
Added:
{ #category : #accessing }
23
Added:
MFTSQLite3Database class >> defaultLocation: aFilePath [
24
Added:
25
Added:
defaultLocation := aFilePath
26
Added:
]
27
Added:
28
Added:
{ #category : #'as yet unclassified' }
29
Added:
MFTSQLite3Database class >> ensureTablesExist [
30
Added:
31
Added:
self defaultConnection
32
Added:
open;
33
Added:
execute: 'CREATE TABLE IF NOT EXISTS "prospects" (
15
34
"id" INTEGER,
16
35
"email" TEXT NOT NULL,
17
36
"date_time" TEXT NOT NULL,
18
37
PRIMARY KEY("id" AUTOINCREMENT)
19
Removed:
)'.
20
Removed:
aMFTDatabase connection execute:
21
Removed:
'CREATE TABLE IF NOT EXISTS "users" (
38
Added:
)';
39
Added:
execute: 'CREATE TABLE IF NOT EXISTS "users" (
22
40
"id" INTEGER UNIQUE,
23
Removed:
"username" TEXT,
24
Removed:
"password_hash" BLOB,
41
Added:
"username" TEXT NOT NULL,
42
Added:
"password_hash" BLOB NOT NULL,
25
43
"real_first_name" TEXT,
26
44
"real_last_name" TEXT,
27
45
"date_of_birth" TEXT,
28
46
PRIMARY KEY("id" AUTOINCREMENT)
29
Removed:
)'
47
Added:
)';
48
Added:
close
30
49
]
31
50
51
Added:
{ #category : #'class initialization' }
52
Added:
MFTSQLite3Database class >> initialize [
53
Added:
54
Added:
defaultLocation := (Smalltalk imageDirectory / 'mft.sqlite3') fullName
55
Added:
]
56
Added:
57
Added:
{ #category : #'instance creation' }
58
Added:
MFTSQLite3Database class >> newFromDefault [
59
Added:
60
Added:
^ self on: defaultLocation
61
Added:
]
62
Added:
63
Added:
{ #category : #'as yet unclassified' }
64
Added:
MFTSQLite3Database class >> registerNewUser: aMFTUser [
65
Added:
66
Added:
self defaultConnection
67
Added:
open;
68
Added:
execute:
69
Added:
'INSERT INTO users(username,password_hash,account_creation_date_time) VALUES (?, ?, ?);'
70
Added:
with: {
71
Added:
aMFTUser username.
72
Added:
aMFTUser passwordHash.
73
Added:
DateAndTime now asUTC rounded };
74
Added:
close
75
Added:
]
76
Added:
32
77
{ #category : #setting }
33
78
MFTSQLite3Database class >> storeProspectEmail: anEmail [
34
79
35
Removed:
| connection |
36
Removed:
connection := (self openOn:
37
Removed:
(Smalltalk imageDirectory / 'mft.sqlite3') fullName)
38
Removed:
connection.
39
Removed:
connection
80
Added:
self defaultConnection
81
Added:
open;
40
82
execute: 'INSERT INTO prospects(email,date_time) VALUES (?, ?);'
41
83
value: anEmail
42
Removed:
value: DateAndTime now asUTC rounded asString.
43
Removed:
connection close
84
Added:
value: DateAndTime now asUTC rounded asString;
85
Added:
close
44
86
]
45
87
46
88
{ #category : #'as yet unclassified' }
@@ -54,4 +96,18 @@
54
96
MFTSQLite3Database >> selectAll: aTable [
55
97
56
98
^ self select: '*' from: aTable
99
Added:
]
100
Added:
101
Added:
{ #category : #'as yet unclassified' }
102
Added:
MFTSQLite3Database >> updateLoginDateAndTime: aMFTUser [
103
Added:
104
Added:
connection
105
Added:
open;
106
Added:
execute: 'UPDATE users
107
Added:
SET last_login_date_time = ?
108
Added:
WHERE username = ?'
109
Added:
with: {
110
Added:
DateAndTime now asUTC rounded.
111
Added:
aMFTUser username };
112
Added:
close
57
113
]
src/MyFitnessTracker/MFTSession.class.st
@@ -78,8 +78,7 @@
78
78
MFTSession >> unregistered [
79
79
80
80
db connection close.
81
Removed:
user := nil.
82
Removed:
super unregistered
81
Added:
user := MFTUser new
83
82
]
84
83
85
84
{ #category : #accessing }
src/MyFitnessTracker/MFTTab.class.st
@@ -1,14 +0,0 @@
1
Removed:
Class {
2
Removed:
#name : #MFTTab,
3
Removed:
#superclass : #SBSComponent,
4
Removed:
#instVars : [
5
Removed:
'title'
6
Removed:
],
7
Removed:
#category : #'MyFitnessTracker-Components'
8
Removed:
}
9
Removed:
10
Removed:
{ #category : #accessing }
11
Removed:
MFTTab >> title [
12
Removed:
13
Removed:
^ title asString
14
Removed:
]
src/MyFitnessTracker/MFTUser.class.st
@@ -7,8 +7,8 @@
7
7
'dateOfBirth',
8
8
'realFirstName',
9
9
'realLastName',
10
Removed:
'lastConnectionDateTime',
11
Removed:
'isLoggedIn'
10
Added:
'isLoggedIn',
11
Added:
'lastLoginDateAndTime'
12
12
],
13
13
#category : #'MyFitnessTracker-Model'
14
14
}
@@ -74,15 +74,15 @@
74
74
]
75
75
76
76
{ #category : #accessing }
77
Removed:
MFTUser >> lastConnectionDateTime [
77
Added:
MFTUser >> lastLoginDateAndTime [
78
78
79
Removed:
^ lastConnectionDateTime
79
Added:
^ lastLoginDateAndTime
80
80
]
81
81
82
82
{ #category : #accessing }
83
Removed:
MFTUser >> lastConnectionDateTime: aDateAndTime [
83
Added:
MFTUser >> lastLoginDateAndTime: anObject [
84
84
85
Removed:
lastConnectionDateTime := aDateAndTime
85
Added:
lastLoginDateAndTime := anObject
86
86
]
87
87
88
88
{ #category : #accessing }
@@ -100,7 +100,7 @@
100
100
{ #category : #accessing }
101
101
MFTUser >> passwordHashFromString: aString [
102
102
103
Removed:
passwordHash := (SHA256 new hashMessage: aString) asString
103
Added:
passwordHash := SHA256 new hashMessage: aString
104
104
]
105
105
106
106
{ #category : #accessing }
src/MyFitnessTracker/MFTUserHomepageTab.class.st
@@ -1,6 +1,6 @@
1
1
Class {
2
2
#name : #MFTUserHomepageTab,
3
Removed:
#superclass : #MFTTab,
3
Added:
#superclass : #MFTPage,
4
4
#category : #'MyFitnessTracker-Components'
5
5
}
6
6
@@ -15,11 +15,11 @@
15
15
{ #category : #rendering }
16
16
MFTUserHomepageTab >> renderContentOn: html [
17
17
18
Removed:
" html container: [
19
Removed:
" "html displayHeading
18
Added:
html container: [
19
Added:
html displayHeading
20
20
level: 1;
21
Removed:
with: 'Welcome, ' , self session user username , '!'."
22
Removed:
"html unorderedList: [
21
Added:
with: 'Welcome, ' , self session user username , '!'.
22
Added:
html unorderedList: [
23
23
(self session db selectAll: 'prospects') do: [ :prospect |
24
Removed:
html listItem: prospect ] ] ]"
24
Added:
html listItem: prospect ] ] ]
25
25
]
src/MyFitnessTracker/MFTWeightsListTab.class.st
@@ -1,6 +1,6 @@
1
1
Class {
2
2
#name : #MFTWeightsListTab,
3
Removed:
#superclass : #MFTTab,
3
Added:
#superclass : #MFTPage,
4
4
#instVars : [
5
5
'weights'
6
6
],
src/MyFitnessTracker/MFTWorkoutsListTab.class.st
@@ -23,7 +23,7 @@
23
23
"
24
24
Class {
25
25
#name : #MFTWorkoutsListTab,
26
Removed:
#superclass : #MFTTab,
26
Added:
#superclass : #MFTPage,
27
27
#instVars : [
28
28
'workouts'
29
29
],