Problem Statement:

Design Stack Overflow using object-oriented principles.

If you haven't used Stack Overflow before, I highly recommend that you visit https://stackoverflow.com/ and play around to become familiar with its core features. Click here for wiki.

Solution:



Object Oriented Analysis:

Just like how in real world software engineering project the first stage of the software development lifecycle (SDLC) is to gather software requirements from the business analyse the requirements, in a design interview your first task is to have a conversation with your interviewer to gather the requirements he/she has in mind. The interviewer would intentionally keep the problem statement vague to see if you are someone who jumps on implementing something, making a lot of assumptions on your own and not clarifying the requirements. To key to success in object oriented design or low level design interview, as well as in your software engineering career, is to ask a lot of clarifying questions, have critical thinking ability and analytical skills.

Remember that, even though your interviewer might have something very specific for you to design in his/her mind, the onus is on you to come up with different relevant features for the system once you have gotten a hint on what your interviewer wants you to design. You need to ask questions, come up with various features of the system, and then validate them with your interviewer to know if your interviewer is okay with the system having those features or not.

Coming up with various features is not always straightforward. But we would be using the below methodology that would help us figuring different features in a very systematic way:

  • Step #1: Actors: Think about all the actors involved. Figure out all the different types of actors involved and all the different types of users who will be using the system.
  • Step #2. User Activities and Use Cases: For each type of actors, you need to think through the different features that they would be interested in using, and different activities that they would be doing.
  • Step #3. Entities: Determine different core components that will be working together in sync with other to make the system, as a whole, functional. Entities are often non-living things.
The Actors and Entities become Classes that we would need to design. The user activities and use cases become the methods or properties.

So in short, what the above frameworks asks us to do is: start with getting an overall high-level sense of the system you are going to design. Using the information you have so far, start figuring out all user types, and then for each user type figure out all the relevant user activities. Analysing all the user activities will give you all the entities and components that are needed for the system to function.
Remember to ask your interviewer clarifying questions at all steps to accomplish your goal. An integral part of design interviews is to showcase how good you are at requirements gathering and requirements analysis.




Actors:

We have four main actors involved in our system:
  • Unregistered Users: Anyone can search and view questions. You do not need to be a registered users to do these operations.
  • Registered Users: Registered Members can perform all activities that guests can, in addition to which they can add/remove questions, answers, and comments. Members can delete and un-delete their questions, answers or comments.
  • Moderators: In addition to all the activities that registered users can perform, moderators can close any question.
  • Admins: In addition to all the activities that registered users can perform, an admins can block or unblock members.


Activities involved and Use Cases:


A quick look at a typical Stackoverflow page will help us come up with different relevant user activities and usecases.





  • Any non-member (guest) can search and view questions. However, to add or upvote a question, they have to become a member.
  • Members should be able to post new questions.
  • Members should be able to add an answer to an open question.
  • Members can add comments to any question or answer.
  • A member can upvote a question, answer or comment.
  • Members can flag (i.e, report as spam or abuse or off-topic) a question, answer or comment, for serious problems or moderator attention.
  • Any member can add a bounty to their question to draw attention.
  • Moderators and admins can close or reopen any question.
  • Members can add tags to their questions. A tag is a word or phrase that describes the topic of the question.
  • Moderators and admins can close a question.
  • Admins can block (ban) or unblock a member if the member's behavior id deemed non-compliant to the community rules.
Remember that during a design interview the onus is on you to be creative and come up with relevant use cases and user activities for the system that you are designing, and getting them validated by the interviewer before you go ahead and write code.

Entities:

Here are the main classes of Stack Overflow System:
  • Question: This class is the central part of our system. It has attributes like Title and Description to define the question. In addition to this, we will track the number of times a question has been viewed or voted on. We should also track the status of a question, as well as closing remarks if the question is closed.
  • Answer: The most important attributes of any answer will be the text and the view count. In addition to that, we will also track the number of times an answer is voted on or flagged. We should also track if the question owner has accepted an answer.
  • Comment: Similar to answer, comments will have text, and view, vote, and flag counts. Members can add comments to questions and answers.
  • Tag: Tags will be identified by their names and will have a field for a description to define them. We will also track daily and weekly frequencies at which tags are associated with questions.
  • Photo: Questions or answers can have photos.
  • Bounty: Each member, while asking a question, can place a bounty to draw attention. Bounties will have a total reputation and an expiry date.
  • Account: We will have four types of accounts in the system, guest, member, admin, and moderator. Guests can search and view questions. Members can ask questions and earn reputation by answering questions and from bounties.


Object Oriented Design and Low Level Implementation:


Question:

We would start our Object Oriented Design with designing the Question class. Let's think about what are the properties associated with Questions in Stack Overflow.

Below is a sample page from Stackoverflow:





  • Questions will have a mandatory title and text. Questions can optionally have one or more photos.
  • Questions will have a creation date and the time when it was last edited by the question asker.
  • A Question has a creator or question asker.
  • Members can answer a Question.
    Members can also put comments to a Question.
  • A Question can be upvoted or downvoted.
    A very interesting edge case to consider is that a user can try to upvote or downvote a question multiple times, but we need to make sure that a member cannot upvote a question that he/she has already upvoted. A user should also not be able to downvote a question that he/she has already downvoted.
    If a downvote is performed followed by an upvote, or an upvote is performed followed by a downvote then the upvote and downvote cancel each other.

  • A Question can be reported if a member thinks it is a spam or an abuse to the system.
  • Question Asker or an Admin can delete a Question.
  • If a satisfactory solution has been found, a Question can be closed.
  • If the Question Asker is in urgent need to get solution to his Question, he/she can add Bounty to his/her Question to get extra attention. A bounty is a special reputation award given to answers. It is funded by the personal reputation of the user who offers it, and is non-refundable.
  • Question asker can optionally associate a Question with one or more tags.
Before we jump on to the class implementation of Question class, let's take a look at the Answer and Comment classes.

Answer:

Answer entity will have below properties:
  • Answer entity has a creator who wrote the answer.
  • Answer will have some text.
  • Answer will be associated with creation date time indicating when it was created, and it should also have last updated date time indicating if the member editted the answer and when.
  • Answer entity can optinally have photos.
  • Members can upvote or downvote an Answer.
  • The creator can delete an Answer.
  • An Answer can be marked as a solution to a question if the Answer satisfied the asker of the question to which this Answer is associated to.
  • People can also comment on an Answer to give their own opinion on that answer.
  • People can report a comment for abuse or spam.
  • If an answer satisfies the question asker and gets a bounty, then the creator of the answer gets the bounty.


Comment:

  • Comment entity has a creator who wrote the answer.
  • Comment will have some text.
  • Comment will be associated with creation date time indicating when it was created, and it should also have last updated date time indicating if the member editted the comment and when.
  • Comment entity can optinally have photos.
  • Members can upvote or downvote an Comment.
  • The creator can delete a Comment.
  • People can report a comment for abuse or spam.


Did you observe anything interesting about Question entity, Comment entity and Answer entity ? They all have the following properties in common:
  • They all have associated creators.
  • They all have associated creation date time and last updated date time.
  • They all have some associated text.
  • They all can have optional photos.
  • Members can upvote or downvote them.
  • They can be deleted by creator and/or Admin. Admin can also reinstate an entity deleted by them.


We would create an abstract class with all these common properties and then Question, Answer and Comment will inherit the abstract class. Please try to learn by heart how we are using Object oriented principles like inheritance in our design. This is super critical.


package OOD.StackOverflow;

/**
 * Created by Abhishek on 10/14/21.
 */
public enum Status {
    OPEN,
    CLOSED,
    DELETED,
    DEFAULT
}



            
package OOD.StackOverflow;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Created by Abhishek on 10/14/21.
 */
public abstract class TextPhotoBasedEntity {  // TextPhotoBasedEntity is an abstract class
                // since we will not be creating an object of this class
                // without specifying if this is a question, answer or comment.

    protected long id; // there is no need to expose id hence private.
                    // id is used to uniquely identify an entity

    protected String text;
    protected long creationDateTime;
    protected long lastUpdated;
    protected Member creator;
    protected List< Photo > photos;
    protected Set< Integer > membersWhoDownvotedThisEntity;
    protected Set< Integer > membersWhoUpvotedThisEntity;
    protected int numberOfUsersReportedThisEntity; // members reported as spam or abuse
    protected Status status;

    public TextPhotoBasedEntity(long id, Member creator, String text, List< Photo > photos) {
        this.id = id;
        status = Status.DEFAULT;
        this.creator = creator;
        this.text = text;

        photos = new ArrayList<>();

        if (photos != null) {
            this.photos = photos;
        }

        membersWhoDownvotedThisEntity = new HashSet<>();
        membersWhoUpvotedThisEntity = new HashSet<>();
        creationDateTime = System.currentTimeMillis();
        lastUpdated = System.currentTimeMillis();

        numberOfUsersReportedThisEntity = 0;
    }

    public boolean equals(Object that) {
        if (that instanceof TextPhotoBasedEntity) {
            return this.id == ((TextPhotoBasedEntity) that).id;
        }
        return false;
    }

    public void upVote(int memberId) {
        if (!membersWhoUpvotedThisEntity.contains(memberId)) { // a member cannot upvote a comment that he/she has already upvoted
            if (membersWhoDownvotedThisEntity.contains(memberId)) {
                // if the member has downvoted this comment in past then upvoting it once just
                // cancels the downvote.
                membersWhoDownvotedThisEntity.remove(memberId);
            } else {
                membersWhoUpvotedThisEntity.add(memberId);
            }
        }
    }

    public void downVote(int memberId) {
        if (!membersWhoDownvotedThisEntity.contains(memberId)) { // a member cannot downvote a comment that he/she has already downvoted
            if (membersWhoUpvotedThisEntity.contains(memberId)) {
                // if the member has upvoted this comment in past then downvoting it once just
                // cancels the upvote.
                membersWhoUpvotedThisEntity.remove(memberId);
            } else {
                membersWhoDownvotedThisEntity.add(memberId);
            }
        }
    }

    // report as abuse or spam
    public void report() {
        numberOfUsersReportedThisEntity++;
    }

    public void updateText(String text) {
        this.text = text;
        lastUpdated = System.currentTimeMillis();
    }

    public void removePhoto(List< Photo > photosToBeDeleted) {
        photos.removeAll(photosToBeDeleted);
        lastUpdated = System.currentTimeMillis();
    }

    public void addPhotos(List< Photo > newPhotosToBeAdded) {
        photos.addAll(newPhotosToBeAdded);
        lastUpdated = System.currentTimeMillis();
    }

    public int getUpvoteCount() {
        return membersWhoUpvotedThisEntity.size();
    }

    public int getDownvoteCount() {
        return membersWhoDownvotedThisEntity.size();
    }

    public Member getCreator() {
        return creator;
    }

    public void delete() { // Admin can delete an entity
        status = Status.DELETED;
    }

    public long getId() {
        return id;
    }

    public String getText() {
        return text;
    }

    public long getCreationDateTime() {
        return creationDateTime;
    }

    public long getLastUpdated() {
        return lastUpdated;
    }

    public List< Photo > getPhotos() {
        return photos;
    }

    public Set< Integer > getMembersWhoDownvotedThisEntity() {
        return membersWhoDownvotedThisEntity;
    }

    public Set< Integer > getMembersWhoUpvotedThisEntity() {
        return membersWhoUpvotedThisEntity;
    }

    
    public int getVoteCount() {
        return getUpvoteCount() - getDownvoteCount();    
    }

    public int getNumberOfUsersReportedThisEntity() {
        return numberOfUsersReportedThisEntity;
    }

    public Status getStatus() {
        return status;
    }

}

    


            
package OOD.StackOverflow;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Abhishek on 10/12/21.
 */
public class Question extends TextPhotoBasedEntity{

    private String title;
    private Status status;
    private Bounty bounty;

    private List< Tag > tags;
    private List< Comment > comments;
    private List< Answer > answers;

    public Question(long id, Member askingMember, String title, String text, List photos, List tags, Bounty bounty) {

        super(id, askingMember, text, photos);

        status = Status.OPEN;
        this.title = title;
        this.bounty = bounty;

        if (tags != null) {
            this.tags = tags;
        } else {
            this.tags = new ArrayList<>();
        }

        comments = new ArrayList<>();
        answers = new ArrayList<>();
    }

    public void close() { // Question Asker or Admin can close a question due to various reasons like a solution has been found or due to inactivity of users or certain other reaons
        status = Status.CLOSED;
    }

    public void addComment(Comment newComment) {
        comments.add(newComment);
    }

    public void addAnswer(Answer newAnswer) {
        answers.add(newAnswer);
    }

    public String getTitle() {
        return title;
    }

    public Status getStatus() {
        return status;
    }

    public Bounty getBounty() {
        return bounty;
    }

    public List< Tag > getTags() {
        return tags;
    }

    public List< Comment > getComments() {
        return comments;
    }

    public List< Answer > getAnswers() {
        return answers;
    }

}

    


            
package OOD.StackOverflow;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Abhishek on 10/12/21.
 */
public class Answer extends TextPhotoBasedEntity{

    private boolean solvedProblem; // is this answer a proper solution to the question ?
    private List< Comment > comments;

    public Answer(long id, Member creatingMember, String text, List< Photo > photos) {
        super(id, creatingMember, text, photos);

        comments = new ArrayList<>();
    }

    public void markAsASolution() {
        solvedProblem = true;
    }

    public void updateText(String text) {
        this.text = text;
        lastUpdated = System.currentTimeMillis();
    }

    public void addComment(Comment newComment) {
        comments.add(newComment);
    }

    public void receiveBounty(int reputation) {
        creator.receiveBounty(reputation);
    }

    public boolean isSolvedProblem() {
        return solvedProblem;
    }

    public List< Comment > getComments() {
        return comments;
    }

}

    


            
package OOD.StackOverflow;

import java.util.List;

/**
 * Created by Abhishek on 10/12/21.
 */
public class Comment extends TextPhotoBasedEntity{

    public Comment(Member commenter, String text, List< Photo > photos) {
        super(commenter, text, photos);
    }

}

    


Photo:

A Photo will have:
  • an id
  • path to where the photo is stored
  • creation time
  • member who created it.


            
package OOD.StackOverflow;

/**
 * Created by Abhishek on 10/12/21.
 */
public class Photo {
    private long id;
    private String photoPath;
    private long creationDate;
    private Member creatingMember;

    public Photo(long id, String photoPath, Member creator) {
        this.id = id;
        this.photoPath = photoPath;
        creationDate = System.currentTimeMillis();
        creatingMember = creator;
    }

    public boolean equals(Object that) {
        if (that instanceof Photo) {
            return this.id == ((Photo) that).id;
        }
        return false;
    }

    public long getId() {
        return id;
    }

    public String getPhotoPath() {
        return photoPath;
    }

    public long getCreationDate() {
        return creationDate;
    }

    public Member getCreatingMember() {
        return creatingMember;
    }

}



Bounty:


Properties of Bounty:
  • Bounty specifies how much reputation a member is going to get if his/her answer satisfies the question asker.
  • Bounty has an expiration date.
  • Question Asker can modify the reputation associated with the Bounty.


            
package OOD.StackOverflow;

import java.util.Date;

/**
 * Created by Abhishek on 10/14/21.
 */
public class Bounty {
    private int reputation;
    private Date expirationdate;

    public Bounty(int reputation, Date expirationDate) {
        this.reputation = reputation;
        this.expirationdate = expirationDate;
    }

    public void modifyReputation(int reputation) {
        this.reputation = reputation;
    }
}

    


Tag:


A Tag only has a text associated with it.

            
package OOD.StackOverflow;

/**
 * Created by Abhishek on 10/15/21.
 */
public class Tag {
    private String text;
    public Tag(String text) {
        this.text = text;
    }
    public String getText() {
        return text;
    }
}

    


Member:

A Member has following properties:
  • Member has a Member ID, Name, Display Name or Username, and Email.
  • The account of the member can be in any of these states: ACTIVE, CLOSED, CANCELED, BLACKLISTED, BLOCKED
  • A member can earn reputation by giving high quality answers to open questions.
In addition a moderator can close a question, and an admin can close a question, and block or unblock a member.
            
package OOD.StackOverflow;

/**
 * Created by Abhishek on 10/12/21.
 */
public class Member {

    public enum AccountStatus{
        ACTIVE,
        CLOSED,
        CANCELED,
        BLACKLISTED,
        BLOCKED
    }

    private long id;
    private AccountStatus accountStatus;
    private String name;
    private String displayName;
    private String email;
    private int reputation;
    private boolean isModerator;
    private boolean isAdmin;

    public Member(long id) {
        accountStatus = AccountStatus.ACTIVE;
    }

    public void closeAccount() {
        accountStatus = AccountStatus.CLOSED;
    }

    public void cancelAccount() {
        accountStatus = AccountStatus.CANCELED;
    }

    public void blacklist() {
        accountStatus = AccountStatus.BLACKLISTED;
    }

    public void block() {
        accountStatus = AccountStatus.BLOCKED;
    }

    public boolean blockMember(Member member) {
        if (isAdmin) {
            member.block();
        }
        return false;
    }

    public boolean unblockMember(Member member) {
        if (isAdmin) {
            member.accountStatus = AccountStatus.ACTIVE;
        }
        return false;
    }

    public boolean closeQuestion(Question question) {
        // only moderator, admin or creator of the question can close a question
        if (isAdmin || isModerator || this.id == question.getCreator().getId()) {
            question.close();
        }
        return false;
    }

    public void promoteToAdmin() {
        isAdmin = true;
    }

    public void promoteToModerator() {
        isModerator = true;
    }

    // a question asker can give bounty to someone who has satisfactorily answered to his/her question
    public boolean giveBountyTo(int bountyReputation, Member receiver) {
        if (bountyReputation <= reputation && this.id != receiver.id) {
            reputation -= bountyReputation;
            receiver.receiveBounty(bountyReputation);
        }
        return false;
    }
    // a member receives bounty if his/her answer to a question
    // satisfies the question asker and the question asker gives the answerer the bounty
    public void receiveBounty(int bountyReputation) {
        reputation += bountyReputation;
    }

    public int getReputation() {
        return reputation;
    }

    public int getId() {
        return id;
    }

    public AccountStatus getStatus() {
        return accountStatus;
    }

    public String getName() {
        return name;
    }

    public String getDisplayName() {
        return displayName;
    }

    public String getEmail() {
        return email;
    }

}

    


You might be thinking why we did not create Admin class and Moderator class which could inherit Member class since a moderator or admin posseses all the properties of a member ? The answer to that is, doing that would not have been a very good design decision, since being Admin or Moderator is not a permanent status. A member can be a moderator or admin for a certain time period and not necessarily for th entire time span of his.her membership. So it only makes sense to keep "being moderator or/and admin" as a property of a member.


Python code:



from enum import Enum


class Status(Enum):
    OPEN = 0
    CLOSED = 1
    DELETED = 2
    DEFAULT = 3



------------------------


import time

from OOD.StackOverflow.Status import Status


class TextPhotoBasedEntity:
    def __init__(self, id, creator, text, photos):
        self.id = 0
        self.text = None
        self.creationDateTime = 0
        self.lastUpdated = 0
        self.creator = None
        self.photos = None
        self.membersWhoDownvotedThisEntity = None
        self.membersWhoUpvotedThisEntity = None
        self.numberOfUsersReportedThisEntity = 0
        self.status = None

        self.id = id
        self.status = Status.DEFAULT
        self.creator = creator
        self.text = text
        photos = []
        if photos is not None:
            self.photos = photos
        self.membersWhoDownvotedThisEntity = set()
        self.membersWhoUpvotedThisEntity = set()
        self.creationDateTime = round(time.time() * 1000)
        self.lastUpdated = round(time.time() * 1000)
        self.numberOfUsersReportedThisEntity = 0

    def equals(self, that):
        if isinstance(that, TextPhotoBasedEntity):
            return self.id == (that).id
        return False

    def upVote(self, memberId):
        if not self.membersWhoUpvotedThisEntity.contains(memberId):
            if self.membersWhoDownvotedThisEntity.contains(memberId):
                self.membersWhoDownvotedThisEntity.remove(memberId)
            else:
                self.membersWhoUpvotedThisEntity.add(memberId)

    def downVote(self, memberId):
        if not self.membersWhoDownvotedThisEntity.contains(memberId):
            if self.membersWhoUpvotedThisEntity.contains(memberId):
                self.membersWhoUpvotedThisEntity.remove(memberId)
            else:
                self.membersWhoDownvotedThisEntity.add(memberId)

    def report(self):
        self.numberOfUsersReportedThisEntity += 1

    def updateText(self, text):
        self.text = text
        self.lastUpdated = round(time.time() * 1000)

    def removePhoto(self, photosToBeDeleted):
        self.photos.removeAll(photosToBeDeleted)
        self.lastUpdated = round(time.time() * 1000)

    def addPhotos(self, newPhotosToBeAdded):
        self.photos.extend(newPhotosToBeAdded)
        self.lastUpdated = round(time.time() * 1000)

    def getUpvoteCount(self):
        return self.membersWhoUpvotedThisEntity.size()

    def getDownvoteCount(self):
        return self.membersWhoDownvotedThisEntity.size()

    def getCreator(self):
        return self.creator

    def delete(self):
        self.status = Status.DELETED

    def getId(self):
        return self.id

    def getText(self):
        return self.text

    def getCreationDateTime(self):
        return self.creationDateTime

    def getLastUpdated(self):
        return self.lastUpdated

    def getPhotos(self):
        return self.photos

    def getMembersWhoDownvotedThisEntity(self):
        return self.membersWhoDownvotedThisEntity

    def getMembersWhoUpvotedThisEntity(self):
        return self.membersWhoUpvotedThisEntity

    def getVoteCount(self):
        return self.getUpvoteCount() - self.getDownvoteCount()

    def getNumberOfUsersReportedThisEntity(self):
        return self.numberOfUsersReportedThisEntity

    def getStatus(self):
        return self.status



------------------------



from OOD.StackOverflow.Status import Status
from OOD.StackOverflow.TextPhotoBasedEntity import TextPhotoBasedEntity


class Question(TextPhotoBasedEntity):
    def __init__(self, id, askingMember, title, text, photos, tags, bounty):
        self._title = None
        self._status = None
        self._bounty = None
        self._tags = None
        self._comments = None
        self._answers = None

        super().__init__(id, askingMember, text, photos)
        self._status = Status.OPEN
        self._title = title
        self._bounty = bounty
        if tags is not None:
            self._tags = tags
        else:
            self._tags = []
        self._comments = []
        self._answers = []

    def close(self):
        self._status = Status.CLOSED

    def addComment(self, newComment):
        self._comments.append(newComment)

    def addAnswer(self, newAnswer):
        self._answers.append(newAnswer)

    def getTitle(self):
        return self._title

    def getStatus(self):
        return self._status

    def getBounty(self):
        return self._bounty

    def getTags(self):
        return self._tags

    def getComments(self):
        return self._comments

    def getAnswers(self):
        return self._answers




---------------------------------------



import time

from OOD.StackOverflow.TextPhotoBasedEntity import TextPhotoBasedEntity


class Answer(TextPhotoBasedEntity):
    def __init__(self, id, creatingMember, text, photos):
        self._solvedProblem = False
        self._comments = None

        super().__init__(id, creatingMember, text, photos)
        self._comments = []

    def markAsASolution(self):
        self._solvedProblem = True

    def updateText(self, text):
        self.text = text
        lastUpdated = round(time.time() * 1000)

    def addComment(self, newComment):
        self._comments.append(newComment)

    def receiveBounty(self, reputation, creator=None):
        creator.receiveBounty(reputation)

    def isSolvedProblem(self):
        return self._solvedProblem

    def getComments(self):
        return self._comments



-----------------------------------------------



from OOD.StackOverflow.TextPhotoBasedEntity import TextPhotoBasedEntity


class Comment(TextPhotoBasedEntity):
    def __init__(self, commenter, text, photos):
        super().__init__(commenter, text, photos)




--------------------------------------------------



import time


class Photo:
    def __init__(self, id, photoPath, creator):
        self._id = id
        self._photoPath = photoPath
        self._creationDate = round(time.time() * 1000)
        self._creatingMember = creator

    def equals(self, that):
        if isinstance(that, Photo):
            return self._id == (that)._id
        return False

    def getId(self):
        return self._id

    def getPhotoPath(self):
        return self._photoPath

    def getCreationDate(self):
        return self._creationDate

    def getCreatingMember(self):
        return self._creatingMember



------------------------------------------------------



class Bounty:
    def __init__(self, reputation, expirationDate):
        self._reputation = reputation
        self._expirationdate = expirationDate

    def modifyReputation(self, reputation):
        self._reputation = reputation



----------------------------------------------------


class Tag:
    def __init__(self, text):
        self._text = text

    def getText(self):
        return self._text



----------------------------------------------------


from enum import Enum


class AccountStatus(Enum):
    ACTIVE = 0
    CLOSED = 1
    CANCELED = 2
    BLACKLISTED = 3
    BLOCKED = 4


class Member:

    def __init__(self, id):
        self._id = 0
        self._accountStatus = 0
        self._name = None
        self._displayName = None
        self._email = None
        self._reputation = 0
        self._isModerator = False
        self._isAdmin = False

        self._accountStatus = AccountStatus.ACTIVE

    def closeAccount(self):
        self._accountStatus = AccountStatus.CLOSED

    def cancelAccount(self):
        self._accountStatus = AccountStatus.CANCELED

    def blacklist(self):
        self._accountStatus = AccountStatus.BLACKLISTED

    def block(self):
        self._accountStatus = AccountStatus.BLOCKED

    def blockMember(self, member):
        if self._isAdmin:
            member.block()
        return False

    def unblockMember(self, member):
        if self._isAdmin:
            member._accountStatus = AccountStatus.ACTIVE
        return False

    def closeQuestion(self, question):
        if self._isAdmin or self._isModerator or self._id == question.getCreator().getId():
            question.close()
        return False

    def promoteToAdmin(self):
        self._isAdmin = True

    def promoteToModerator(self):
        self._isModerator = True

    def giveBountyTo(self, bountyReputation, receiver):
        if bountyReputation <= self._reputation and self._id != receiver._id:
            self._reputation -= bountyReputation
            receiver.receiveBounty(bountyReputation)
        return False

    def receiveBounty(self, bountyReputation):
        self._reputation += bountyReputation

    def getReputation(self):
        return self._reputation

    def getId(self):
        return self._id

    def getStatus(self):
        return self._accountStatus

    def getName(self):
        return self._name

    def getDisplayName(self):
        return self._displayName

    def getEmail(self):
        return self._email

   

    



Still hungry to learn more? You might find the below chapters interesting:




Instructor:



If you have any feedback, please use this form: https://thealgorists.com/Feedback.



Help Your Friends save 40% on our products

wave