Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fire - Roshni and Pauline - Slack CLI #6

Open
wants to merge 60 commits into
base: master
Choose a base branch
from

Conversation

ghostfruitleaf
Copy link

Assignment Submission: Slack CLI

Congratulations! You're submitting your assignment. Please reflect on the assignment with these questions.

Reflection

Question Answer
How did you go about exploring the Slack API? Did you learn anything that would be useful for your next project involving an API? We spent time reading through the Slack API documentation and testing things out with Postman. We learned various things, such as needing to use User ID to send to both channels and users with chat.postMessage or being able to customize the bot's username and emoji.
Give a short summary of the request/response cycle. Where does your program fit into that scheme? The client (e.g. our program) makes a request to the server (e.g. Slack API). The server processes the request and returns a response to the client. The client can then look at the response and determine what to do next and they may choose to send another request and continue with the request/response cycle.
How does your program check for and handle errors when using the Slack API? In our program, we raise a SlackAPIError if the user enters a message that is over 4000 characters, receives a "false" ok response, or a non-200 code response. We also raise an ArgumentError if the user enters an invalid emoji.
How did the design and organization of your project change over time? Although we knew from the beginning that we wanted to include a Recipient, User, Channel, and Workspace class, as we progressed through the project and began working on the optional requirements, we decided to add a Bot class that would inherit from the User class to address customizing the bot's emoji and username.
Did you use any of the inheritance idioms we've talked about in class? How? We used inheritance idioms in the form of abstract classes and template methods. Recipient was an abstract class that was the parent of the User and Channel classes and it had template methods (details and list all methods). Bot in turn inherited from User.
How does VCR aid in testing a program that uses an API? VCR is helpful when testing a program that uses an API because it records HTTP interactions (“cassettes”) and allows you to replay them whenever you need to without having to make another API call.

roshni-patel and others added 30 commits October 6, 2020 16:41
…l.rb, output should be hash rather than returnable
…clarification line in slack.rb to reprint menu after every action, added sleep to get in recipient in case of infinite loop
roshni-patel and others added 29 commits October 7, 2020 20:35
…share in details, completed adjusting user_test, started adjusting workspace_test
…d send_message to account for new parameters
Copy link

@kaidamasaki kaidamasaki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent job! There were some small things I called out in the comments but overall your solution was really strong.

You did an extremely good job of turning the UML diagrams we gave you into a coherent set of classes that all work well together and have clearly defined responsibilities. 😃

Slack CLI

Major Learning Goals/Code Review

Criteria yes/no, and optionally any details/lines of code to reference
Practices best practices working with APIs. The .env is not checked into git, and no API token was directly used in the Ruby code without ENV. ✔️
Practices error handling with APIs. For all pieces of code that make an API call, it handles API requests that come back with errors/error status codes appropriately. ✔️
Implements inheritance and inheritance idioms. There is a Recipient class. User and Channel inherit from Recipient. In Recipient, there are appropriate methods defined that are used in both User and Channel. Some may be implemented. Some may be template methods. ✔️
Practices clean code. lib/slack.rb only interacts with Workspace to show a separation of responsibilities. Complex logic is broken into smaller helper methods. ✔️
Practices instance methods vs. class methods appropriately. The methods to list all Channels or Users is likely a class method within those respective classes. ✔️
Practices best practices for testing. The project has and uses VCR mocking when running tests, and can run offline. ✔️
Practices writing tests. The User, Channel, and Workspace classes have unit tests. ✔️
Practices writing tests. There are tests for sending messages (the location of these tests may differ, but is likely in Recipient) ✔️
Practices git with at least 15 small commits and meaningful commit messages ✔️

Functional Requirements

Functional Requirement yes/no
As a user of the CLI program, I can list users and channels ✔️
As a user of the CLI program, I can select users and channels ✔️
As a user of the CLI program, I can show the details of a selected user or channel ✔️
As a user of the CLI program, when I input something inappropriately, the program runs without crashing ✔️

Overall Feedback

Overall Feedback Criteria yes/no
Green (Meets/Exceeds Standards) 7+ in Code Review && 3+ in Functional Requirements ✔️
Yellow (Approaches Standards) 6+ in Code Review && 2+ in Functional Requirements
Red (Not at Standard) 0-5 in Code Review or 0,1 in Functional Reqs, or assignment is breaking/doesn’t run with less than 5 minutes of debugging

Code Style Bonus Awards

Was the code particularly impressive in code style for any of these reasons (or more...?)

Quality Yes?
Perfect Indentation
Elegant/Clever
Descriptive/Readable
Concise
Logical/Organized

# we don't want to break the program here because the reason
# could be anything
raise SlackApiError, "Error: #{response.parsed_response['error']}. Please try again"
return false

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to return false here. The raise will make sure this line never runs.

url = 'https://slack.com/api/auth.test'
query = {token: Bot.token}
sleep(0.5)
response = HTTParty.get(url, query: query)['user_id']

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should check the response code of this request.


def self.list_all
bots = super
bots = bots.filter{ |user| user.is_bot || user.slack_id == "USLACKBOT"}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice touch filtering out the bot users.

end

def details
tp self, :slack_id, :name, :topic, :member_count

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should leave the actual printing of things up to slack.rb. (This is why your unit tests print out tables in the middle.)

url = "https://slack.com/api/conversations.list"
param = {token: Channel.token}
raw_channels = Channel.get(url, param)['channels']
all_channels = raw_channels.map do |channel|

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice use of map!


attr_reader :real_name, :time_zone, :is_bot

def initialize(slack_id:, name:, real_name:, time_zone: "Pacific Daylight Time", is_bot: false)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Configurable timezones! 🎉

raw_users = User.get(url, param)['members']
all_users = [] # to skip over deleted users
raw_users.each do |member|
next if member['deleted']

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like your attention to detail with skipping bad entries like this.

end
end
end
return nil # returns nil to indicate user not found

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might raise a UserNotFoundError instead of returning nil.

You can forget to check for a nil return value but you notice right away if you got an exception.

Comment on lines +52 to +53
# NOTE: We didn't write a test to check whether the token is valid because that has already been tested in the
# .get method in Recipient.rb from which it inherits, meaning it should work here too for channel.rb

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice documentation! 😃

Comment on lines +39 to +42
message = ""
4005.times do
message += "A"
end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ruby actually has built in syntax for this (for some reason):

Suggested change
message = ""
4005.times do
message += "A"
end
message = "A" * 4005

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants