//SPDX-License-Identifier: MIT pragma solidity 0.7.1; contract Forum { //----------------------------------------USER---------------------------------------- struct User { string username; // TODO: set an upper bound instead of arbitrary string uint[] topicIDs; // IDs of the topics the user created uint[] postIDs; // IDs of the posts the user created uint timestamp; bool signedUp; // Helper variable for hasUserSignedUp() } mapping (address => User) users; mapping (string => address) userAddresses; event USER_SIGNED_UP(string username, address userAddress); event USERNAME_UPDATED(string newName, string oldName, address userAddress); function signUp(string memory username) public returns (bool) { require (!hasUserSignedUp(msg.sender), "User has already signed up."); require(!isUserNameTaken(username), "Username is already taken."); users[msg.sender] = User(username, new uint[](0), new uint[](0), block.timestamp, true); userAddresses[username] = msg.sender; emit USER_SIGNED_UP(username, msg.sender); return true; } function updateUsername(string memory newUsername) public returns (bool) { require (hasUserSignedUp(msg.sender), "User hasn't signed up yet."); require(!isUserNameTaken(newUsername), "Username is already taken."); string memory oldUsername = getUsername(msg.sender); delete userAddresses[users[msg.sender].username]; users[msg.sender].username = newUsername; userAddresses[newUsername] = msg.sender; emit USERNAME_UPDATED(newUsername, oldUsername, msg.sender); return true; } function getUsername(address userAddress) public view returns (string memory) { require (hasUserSignedUp(userAddress), "User hasn't signed up yet."); return users[userAddress].username; } function getUserAddress(string memory username) public view returns (address) { return userAddresses[username]; } function hasUserSignedUp(address userAddress) public view returns (bool) { return users[userAddress].signedUp; } function isUserNameTaken(string memory username) public view returns (bool) { if (getUserAddress(username)!=address(0)) return true; return false; } function getUserTopics(address userAddress) public view returns (uint[] memory) { require (hasUserSignedUp(userAddress), "User hasn't signed up yet."); return users[userAddress].topicIDs; } function getUserPosts(address userAddress) public view returns (uint[] memory) { require (hasUserSignedUp(userAddress), "User hasn't signed up yet."); return users[userAddress].postIDs; } function getUserDateOfRegister(address userAddress) public view returns (uint) { require (hasUserSignedUp(userAddress), "User hasn't signed up yet."); return users[userAddress].timestamp; } //----------------------------------------POSTING---------------------------------------- struct Topic { uint topicID; address author; uint timestamp; uint[] postIDs; } struct Post { uint postID; address author; uint timestamp; uint topicID; } uint numTopics; // Total number of topics uint numPosts; // Total number of posts mapping (uint => Topic) topics; mapping (uint => Post) posts; event TOPIC_CREATED(uint topicID, uint postID); event POST_CREATED(uint postID, uint topicID); function createTopic() public returns (uint, uint) { require(hasUserSignedUp(msg.sender)); // Only registered users can create topics //Creates topic uint topicID = numTopics++; topics[topicID] = Topic(topicID, msg.sender, block.timestamp, new uint[](0)); users[msg.sender].topicIDs.push(topicID); //Adds first post to topic uint postID = numPosts++; posts[postID] = Post(postID, msg.sender, block.timestamp, topicID); topics[topicID].postIDs.push(postID); users[msg.sender].postIDs.push(postID); emit TOPIC_CREATED(topicID, postID); return (topicID, postID); } function createPost(uint topicID) public returns (uint) { require(hasUserSignedUp(msg.sender)); // Only registered users can create posts require(topicID