HW 3: Trees and Objects

Due: Tue, Oct 8 2024 at 9:00 PM EST

Released: Wed, Oct 2 2024

The goal of this assignment is to get practice with designing and developing programs that operate on tree-shaped data and to get practice implementing methods on Python classes.

Setup

In addition, create the following empty files:

The Assignment

Part 1: For the love of Newton

Tim has been invited to give a talk at Woolsthorpe Manor, the famous location where Isaac Newton reportedly came up with the law of gravity. While touring the estate, you pass by the apple tree. Tim thinks that inspiration could be found at the top of the tree, but would perhaps be wiser not to make the attempt. Exactly how far is it from the top of the tree to the bottom? You’ll help by showing Tim a simulation of this idea on HTML trees.

Task 1: Implement tree_height. computes the maximum distance from the root to any leaf. This function should take an HTMLTree and return an integer. The height of a tree with only the root and no children is 1; the height of a tree with children is the maximum height of any of its children plus 1.

Task 2: Implement has_strong_grandchildren. This function should take an HTMLTree and return a boolean. It should return True if any of the grandchildren of the root of the tree have the "strong" tag, and False otherwise. Note that it doesn’t matter whether the root of the tree or any of its children are strong, we only care about the grandchildren.

Part 1.1: Testing

Task 3: Write tests for your tree_height and has_strong_grandchildren functions in tree_test.py.

Some of the tests you write will require you to create HTML trees. You can create an HTML tree using the HTMLTree class, which is defined in htmltree.py. You should test for both the base cases and edge cases.

Part 2: Getting the message

In homework two, Tim set up a social network to connect students with similar interests. Now, he wants to grow the platform by allowing users to interact with each other through messaging.

Part 2.1: Message Center

For this part, you’ll implement a messaging application–think WhatsApp. Your application will track messages (as a list of Message objects, defined above) and groups, which are sets of users. Users can send messages either to other users or to a group; sending a message to a group results in it being sent to every user in the group. Your messaging application will be implemented as a class called MessageCenter.

You should write code for this part in messagecenter.py. The stencil file, linked above, contains code implementing the Message class, as well as the method definitions for the MessageCenter class.

Task 4: Implement __init__. The __init__ method doesn’t need to take any arguments besides self. It should add messages and groups fields to the object; these should be an empty list responsible for keeping track of the messages and an empty dictionary in charge of the different groups present in the message center, respectively.

Task 5: Implement add_user_to_group. This method should take (in addition to self) the name of a group (a string) and the name of a user (also a string). It should add a group with the given name if it doesn’t exist, and then add the named user to the group if it’s not already in the group.

Task 6: Implement add_direct_message. add_direct_message should take (in addition to self) two users and a message body. It should create a message with the given users and body and store it in the messages list.

Task 7: Implement add_group_message. add_group_message should take (in addition to self) a user, a group, and a message body. If the given group exists, it should add messages with the given body from the given user to every member of the group.

Task 8: Implement next_message. next_message should take (in addition to self) a user and return the first unread message in the messages list addressed to that user. Before returning the message, it should mark the message as read using the mark_read method.

Task 9: Implement message_history. message_history should take (in addition to self) two users and return all of the messages (read or unread) between those two users–messages from the first user to the second user and vice versa.

Part 2.2: Privacy

We have received feedback from our users expressing a desire for their messages to be encrypted to ensure their privacy. However, we currently analyze the content of users’ messages to screen for potentially harmful content.

Task 10: To get a deeper understanding of the issue read this article on WhatsApp end to end encryption.

Note: You should be able to access the mentioned articles without requiring any subscription. You should sign in through google using your brown .edu email.

Task 11: Describe situations where encryption might be a lifeline versus when it could harbor malicious activities. Does your stance on the balance between individual privacy and collective security change based on these contexts? Write your response in the README.

Part 2.3: Metadata

After reviewing various solutions, Tim has concluded that a good compromise between privacy and security would be to incorporate end-to-end encryption for the content of messages while retaining metadata about the context behind those messages for the sake of moderation. While delving into the details of encryption is beyond the scope of this course, we will be adding metadata to our messages.

Task 12: Modify the __init__ field in the Message class so that, in addition to keeping track of the sender and recipient, we keep track of the timestamp and length of a message in self.timestamp and self.length respectively. To get the date and time of a message, use the datetime python library. You can read the documentation for the datetime library here: datetime (use the .now() function).

After implementing metadata answer the following two questions in your README:

Task 13: What other metadata can you think of that might be useful for better understanding the context surrounding an encrypted message?

Task 14: If we stopped keeping track of the sender and recipient(s) of a message, how could you use the metadata we implemented, and the metadata you came up with in your last response to identify the sender and recipient(s) of a message? (Hint: if you are stuck, read Using Metadata to find Paul Revere).

While encryption plays a pivotal role in ensuring security and privacy from intermediaries like the company relaying messages, hackers, and third parties, it only addresses concerns about unauthorized access. Privacy, however, is not only about external threats; it also deals with the control individuals have over their data, even when it is in the hands of authorized recipients. This is where European Privacy Laws under the GDPR (General Data Protection Regulation) come into play. One of the key principles of GDPR is the “right to be forgotten,” which means that individuals can request the deletion of their data. In compliance with this principle, we will implement a function that allows users to delete their account and all messages sent from it.

Task 15: Implement delete_account. delete_account should take (in addition to self) a user and remove all messages sent by that user from the message center. It should also remove the user from any groups they are a part of.

Task 16: What are some of the negative implications of giving users more agency over their data, particularly in scenarios where past messages may have legal, historical, or societal importance? Write your response in the README.

Part 2.4: Testing

Task 17: Write tests for your MessageCenter class in messagecenter_test.py. You should test for both the base cases and edge cases.

Submission

Hand in the following files to Gradescope when submitting the assignment:

Please don’t put your name in your code files, as we grade anonymously. If you have any questions about the assignment, please post on Ed.

You can only use a maximum of 3 late days per assignment. If the assignment is late (and you do NOT have anymore late days) no credit will be given.