Connecting our FriendsList to our web service

To get our FriendsList talking to our web service, we first need an instance of our new Requester. We will also import messagebox, so that we can show some pop-up windows if there are any errors:

import tkinter.messagebox as msg
from requester import Requester
...
def __init__(self, **kwargs):
...
self.requester = Requester()
...

With this in place, we can write the actual login and create_account methods:

def login(self):
username = self.username_entry.get()
real_name = self.real_name_entry.get()

if self.requester.login(username, real_name):
self.username = username
self.real_name = real_name

self.show_friends()
else:
msg.showerror("Failed", f"Could not log in as {username}")

To log in, we first use the get method to retrieve the text inside our two Entry widgets, then pass them to the login method of our requester.

If the call to the web service is successful, we set the current username and real_name to attributes of this class, then call the show_friends method, which will display our test friend as before.

If the provided details do not exist in our database, we will receive a negative response from our web service. We will show this to the user using a message box, letting them know they were not able to log in.

If they instead pick the Create Account button, we will call this method:

def create_account(self):
username = self.username_entry.get()
real_name = self.real_name_entry.get()

if self.requester.create_account(username, real_name):
self.username = username
self.real_name = real_name

self.show_friends()
else:
msg.showerror("Failed", "Account already exists!")

This method is very similar to the login method, but calls the create_account method of our requester and displays a different message if the call to the web service returned a negative response.

You can now run your friendslist.py file and try creating an account and logging in.

Once logged in, you will still see the placeholder friend which we set up last chapter. Since we have a database full of accounts now, we can go ahead and replace this with the other people in our database.

To make our FriendsList display existing users, we need to create a method in our Requester which will fetch them all:

def get_all_users(self):
endpoint = "/get_all_users"
users = self.request("GET", endpoint)

return json.loads(users)

The endpoint to fetch all users is a GET endpoint which takes no parameters; so, we only need to specify the endpoint argument in order to make this request.

As our web service returns a JSON object with no particular key, we can just parse it using the json module's loads method and return it to our FriendsList.

Now, we can loop over the returned users and display them in our application:

def load_friends(self):
all_users = self.requester.get_all_users()

for user in all_users:
if user['username'] != self.username:
friend_frame = ttk.Frame(self.canvas_frame)

We call the get_all_users method we just wrote, then use a for loop to iterate over each user. This user will be a dictionary containing their username and real name.

Since we don't need to be able to talk to ourselves, we can ignore a user who has a username matching the one we have set as our username attribute.

For each user, we will create a Frame to hold their related widgets. These widgets will be the same as they were before:

profile_photo = tk.PhotoImage(file="images/avatar.png")
profile_photo_label = ttk.Label(friend_frame, image=profile_photo)
profile_photo_label.image = profile_photo

friend_name = ttk.Label(friend_frame, text=user['real_name'], anchor=tk.W)

message_this_friend = partial(self.open_chat_window, username=user["username"], real_name=user["real_name"])
message_button = ttk.Button(friend_frame, text="Chat", command=message_this_friend)

There are two main changes we have made to the widgets this time – the friend_name Label now contains the real_name attribute from the user dictionary, and each Chat button will now need to open a specific conversation window (which we will make adjustments for next).

In order to create a different function for each user in our dictionary, we will be using a partial function. This allows us to freeze the arguments of a provided function. Here, we have given the open_chat_window method and frozen the username and real_name arguments as those from our dictionary.

We then finish off the method by packing our widgets, as normal:

profile_photo_label.pack(side=tk.LEFT)
friend_name.pack(side=tk.LEFT)
message_button.pack(side=tk.RIGHT)

friend_frame.pack(fill=tk.X, expand=1)

With this method updated, we now need to adjust our open_chat_window method to accept the username and real_name arguments and do something with them:

def open_chat_window(self, username, real_name):
cw = ChatWindow(self, real_name, username, 'images/avatar.png')

As this method just instantiates the ChatWindow class, all we need to do is pass the username and real_name values over to it. We now need to implement these variables in this class, too.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset