Prevent Unauthorised Access¶
Presently our web app is pretty much open to everyone. Even if you are not logged in, you can view the Home, Add and Calendar pages. Although these pages don’t hold sensitive private information, the functionality of these pages depend up a user being logged in:
HomeComponent → displays the user’s assessment
CalendarComponent → displays the user’s assessment timeline
AddComponent → adds the user’s assessment details
This means that if there is no user logged in, then these components will not function correctly. In this tutorial, we will fix that problem.
Planning¶
For the AddComponent and the CalendarComponent we will add a second card with and error message. Then, when the component is loaded, either the default card or the error card will be displayed.
When it comes to home we will choose between loading the HomeComponent or the WelcomeComponent, depending upon the user login status.
Layout¶
AddComponent Layout¶
Open the AddComponent in Design mode.
Choose the current card
Change it’s name from self.card_1 to self.card_details
Add a new card between self.card_details and self.label_message (pay close attention to the brown lines)
Name the new card self.card_error
Add a label to the self.card_error
Change the text to
Please login to access this feature
Change foreground to
#ff0000
Change role to your desired formatting
Change icon to
fa:warning
Change align to
center
CalendarComponent Layout¶
We haven’t added anything to the CalendarComponent, so we will need to add two cards:
call the first one self.card_details
call the second one self.card_error
Leave self.card_details blank, and then change self.card_error to be the same as AddComponent.
Home Page Layout¶
We don’t have to change the layout of the HomeComponent as we will simply load the WelcomeComponent instead. We will worry about the welcomeComponent layout later on.
Code¶
AddComponent code¶
The AddComponent code will simply check if someone is logged in and adjust the visibility of self.card_details and self.card_error accordingly.
Open AddComponent in Code mode.
In the __init__
method add the highlighted code:
11 def __init__(self, **properties):
12 # Set Form properties and Data Bindings.
13 self.init_components(**properties)
14 self.subject = ""
15 self.details = ""
16 self.start = None
17 self.due = None
18
19 # Any code you write here will run before the form opens.
20 self.label_message.visible = False
21 if anvil.users.get_user():
22 self.card_details.visible = True
23 self.card_error.visible = False
24 self.button_add.visible = True
25 else:
26 self.card_details.visible = False
27 self.card_error.visible = True
28 self.button_add.visible = False
Code explaination
line 21 → checks if there is a user currently logged in
lines 22 - 24 → sets the UI to display the elements appropriate for a logged in user
lines 26 - 28 → sets the UI to display the elements appropriate for no logged in user
CalendarComponent code¶
Use the same logic to display the correct elements in the CalendarComponent.
In CalendarComponents __init__
method, add the code below:
11 def __init__(self, **properties):
12 # Set Form properties and Data Bindings.
13 self.init_components(**properties)
14
15 # Any code you write here will run before the form opens.
16 if anvil.users.get_user():
17 self.card_details.visible = True
18 self.card_error.visible = False
19 else:
20 self.card_details.visible = False
21 self.card_error.visible = True
Home page code¶
The Home page code is trickier, since it involves two components. Luckily we have centralised all component loading into the switch_component method in the MainForm. We can check for user status there and load the HomeComponent is a user is logged in or load the WelcomeComponent if there is no user logged in.
Open the MainForm in Code mode.
First, if we are going to load the WelcomeComponent, we need to import it. Add the highlighted code to the import statement.
1from ._anvil_designer import MainFormTemplate
2from anvil import *
3import anvil.server
4import anvil.tables as tables
5import anvil.tables.query as q
6from anvil.tables import app_tables
7import anvil.users
8from ..HomeComponent import HomeComponent
9from ..CalendarComponent import CalendarComponent
10from ..AddComponent import AddComponent
11from ..AccountComponent import AccountComponent
12from ..SetDetailsComponent import SetDetailsComponent
13from ..WelcomeComponent import WelcomeComponent
Now in the switch_component method add the following code:
25 def switch_component(self, state):
26 # set state
27 if state == "home":
28 if anvil.users.get_user():
29 cmpt = HomeComponent()
30 else:
31 cmpt = WelcomeComponent()
32 breadcrumb = self.breadcrumb_stem
line 27 → note this code is only executed when the home page is being loaded
line 28 → checks if there is a user currently logged in
line 29 → loads the HomeComponent
line 30 & 31 → loads the WelcomeComponent is no user is logged in
Testing¶
Launch your website. Your should be logged in. Make sure that you can access all three of the pages we have worked on:
Home
Add
Calendar
Then logout and check all three pages again.
Final code state¶
By the end of this tutorial your code should be the same as below:
Final MainForm¶
1from ._anvil_designer import MainFormTemplate
2from anvil import *
3import anvil.server
4import anvil.tables as tables
5import anvil.tables.query as q
6from anvil.tables import app_tables
7import anvil.users
8from ..HomeComponent import HomeComponent
9from ..CalendarComponent import CalendarComponent
10from ..AddComponent import AddComponent
11from ..AccountComponent import AccountComponent
12from ..SetDetailsComponent import SetDetailsComponent
13from ..WelcomeComponent import WelcomeComponent
14
15
16class MainForm(MainFormTemplate):
17 def __init__(self, **properties):
18 # Set Form properties and Data Bindings.
19 self.init_components(**properties)
20 self.breadcrumb_stem = self.label_title.text
21
22 # Any code you write here will run before the form opens.
23 self.switch_component("home")
24
25 def switch_component(self, state):
26 # set state
27 if state == "home":
28 if anvil.users.get_user():
29 cmpt = HomeComponent()
30 else:
31 cmpt = WelcomeComponent()
32 breadcrumb = self.breadcrumb_stem
33 elif state == "account":
34 cmpt = AccountComponent()
35 breadcrumb = self.breadcrumb_stem + " - Account"
36 elif state == "add":
37 cmpt = AddComponent()
38 breadcrumb = self.breadcrumb_stem + " - Add"
39 elif state == "calendar":
40 cmpt = CalendarComponent()
41 breadcrumb = self.breadcrumb_stem + " - Calendar"
42 elif state == "details":
43 cmpt = SetDetailsComponent()
44 breadcrumb = self.breadcrumb_stem + " - Account - Set Details"
45
46 # execution
47 self.content_panel.clear()
48 self.content_panel.add_component(cmpt)
49 self.label_title.text = breadcrumb
50 self.set_active_link(state)
51
52 def set_active_link(self, state):
53 if state == "home":
54 self.link_home.role = "selected"
55 else:
56 self.link_home.role = None
57 if state == "add":
58 self.link_add.role = "selected"
59 else:
60 self.link_add.role = None
61 if state == "calendar":
62 self.link_calendar.role = "selected"
63 else:
64 self.link_calendar.role = None
65
66 self.link_register.visible = not anvil.users.get_user()
67 self.link_login.visible = not anvil.users.get_user()
68 self.link_account.visible = anvil.users.get_user()
69 self.link_logout.visible = anvil.users.get_user()
70
71 # --- link handlers
72 def link_home_click(self, **event_args):
73 self.switch_component("home")
74
75 def link_calendar_click(self, **event_args):
76 self.switch_component("calendar")
77
78 def link_add_click(self, **event_args):
79 self.switch_component("add")
80
81 def link_account_click(self, **event_args):
82 """This method is called when the link is clicked"""
83 self.switch_component("account")
84
85 def link_register_click(self, **event_args):
86 anvil.users.signup_with_form(allow_cancel=True)
87 self.switch_component("details")
88
89 def link_login_click(self, **event_args):
90 anvil.users.login_with_form(allow_cancel=True)
91 self.switch_component("home")
92
93 def link_logout_click(self, **event_args):
94 anvil.users.logout()
95 self.switch_component("home")
Final AddComponent¶
1from ._anvil_designer import AddComponentTemplate
2from anvil import *
3import anvil.server
4import anvil.tables as tables
5import anvil.tables.query as q
6from anvil.tables import app_tables
7import anvil.users
8
9
10class AddComponent(AddComponentTemplate):
11 def __init__(self, **properties):
12 # Set Form properties and Data Bindings.
13 self.init_components(**properties)
14 self.subject = ""
15 self.details = ""
16 self.start = None
17 self.due = None
18
19 # Any code you write here will run before the form opens.
20 self.label_message.visible = False
21 if anvil.users.get_user():
22 self.card_details.visible = True
23 self.card_error.visible = False
24 self.button_add.visible = True
25 else:
26 self.card_details.visible = False
27 self.card_error.visible = True
28 self.button_add.visible = False
29
30 def button_add_click(self, **event_args):
31 # validation
32 if not self.text_box_subject.text:
33 self.display_error("Subject name needed")
34 elif not self.text_box_details.text:
35 self.display_error("Assessment details needed")
36 elif not self.date_picker_start.date:
37 self.display_error("Start date needed")
38 elif not self.date_picker_due.date:
39 self.display_error("Due date needed")
40 else:
41 self.subject = self.text_box_subject.text
42 self.details = self.text_box_details.text
43 self.start = self.date_picker_start.date
44 self.due = self.date_picker_due.date
45 self.display_save(f"{self.subject} {self.details} assessment: {self.start} to {self.due} recorded")
46 anvil.server.call('add_assessment', self.subject, self.details, self.start, self.due)
47 self.reset_form()
48
49 def display_error(self, message):
50 self.label_message.visible = True
51 self.label_message.foreground = "#ff0000"
52 self.label_message.icon = "fa:exclamation-triangle"
53 self.label_message.bold = True
54 self.label_message.text = message
55
56 def display_save(self, message):
57 self.label_message.visible = True
58 self.label_message.foreground = "#000000"
59 self.label_message.icon = "fa:save"
60 self.label_message.bold = False
61 self.label_message.text = message
62
63 def reset_form(self):
64 self.subject = ""
65 self.details = ""
66 self.start = None
67 self.due = None
68 self.text_box_subject.text = ""
69 self.text_box_details.text = ""
70 self.date_picker_start.date = None
71 self.date_picker_due.date = None
Finial CalendarComponent¶
1from ._anvil_designer import CalendarComponentTemplate
2from anvil import *
3import anvil.server
4import anvil.tables as tables
5import anvil.tables.query as q
6from anvil.tables import app_tables
7import anvil.users
8
9
10class CalendarComponent(CalendarComponentTemplate):
11 def __init__(self, **properties):
12 # Set Form properties and Data Bindings.
13 self.init_components(**properties)
14
15 # Any code you write here will run before the form opens.
16 if anvil.users.get_user():
17 self.card_details.visible = True
18 self.card_error.visible = False
19 else:
20 self.card_details.visible = False
21 self.card_error.visible = True