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

Add Authentication extra features to Comments tab #41

Merged
merged 19 commits into from
Jun 23, 2020

Conversation

tttzach
Copy link
Owner

@tttzach tttzach commented Jun 11, 2020

Additional features added

Show user e-mail when logged in
Screenshot 2020-06-11 at 6 17 38 PM

Associate user e-mail with user comments
Screenshot 2020-06-11 at 7 43 23 PM

@tttzach tttzach changed the title Authentication extra features Add Authentication extra features Jun 11, 2020
@tttzach tttzach changed the title Add Authentication extra features Add Authentication extra features to Comments tab Jun 11, 2020
@tttzach tttzach changed the base branch from LibrariesAuthentication to master June 17, 2020 19:07
Comment on lines 17 to 21
import com.google.gson.Gson;
import org.javatuples.Pair;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import java.io.IOException;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Owner Author

Choose a reason for hiding this comment

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

Thanks for pointing this out, I just installed a VSCode extension to sort these.

Copy link
Owner Author

Choose a reason for hiding this comment

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

RESOLVED

Comment on lines 35 to 44
if (userService.isUserLoggedIn()) {
String userEmail = userService.getCurrentUser().getEmail();
String logoutUrl = userService.createLogoutURL(redirectUrl);
response.getWriter().println("<p>Logout <a href=\"" + logoutUrl + "\">here</a>.");
Pair<String, String> userInfo = new Pair<>(userEmail, logoutUrl);
sendJson(response, userInfo);
} else {
String loginUrl = userService.createLoginURL(redirectUrl);
response.getWriter().println("<p>Login <a href=\"" + loginUrl + "\">here</a>.");
Pair<String, String> userInfo = new Pair<>("N/A", loginUrl);
sendJson(response, userInfo);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This could be a good candidate for the return early pattern (https://www.itamarweiss.com/personal/2018/02/28/return-early-pattern.html)

Copy link
Owner Author

Choose a reason for hiding this comment

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

This is an interesting pattern, I've never heard of it. Thanks!

Copy link
Owner Author

Choose a reason for hiding this comment

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

RESOLVED

Comment on lines 47 to 51
private void sendJson(HttpServletResponse response, Pair<String, String> userInfo) throws IOException {
Gson gson = new Gson();
String json = gson.toJson(userInfo);
response.getWriter().println(json);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: If you are using this in more than one class, you could consider creating a utility class to share this logic

Copy link
Owner Author

@tttzach tttzach Jun 18, 2020

Choose a reason for hiding this comment

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

@gbuenoandrade I just looked into this, I think this is a great idea. However, one of the sendJson() is defined for Pair and the other is defined for List<String>. Is there a way to add a type-less parameter with two classes that do not share the same abstract class?

Copy link
Collaborator

Choose a reason for hiding this comment

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

gson.toJson accepts Object as parameter, right? Your function could do the same.

Copy link
Owner Author

Choose a reason for hiding this comment

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

I didn't know this, thanks! I've added it!

Copy link
Owner Author

Choose a reason for hiding this comment

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

RESOLVED

Comment on lines 17 to 21
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: imported names order

Copy link
Owner Author

Choose a reason for hiding this comment

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

Thanks for pointing this out, I just installed a VSCode extension to sort these.

Copy link
Owner Author

Choose a reason for hiding this comment

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

RESOLVED

}

function logoutHtml(userEmail, logoutUrl) {
return "<p>Hi " + userEmail + "! Logout <a href=\"" + logoutUrl + "\">here</a>.";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe use a template literal?

Copy link
Owner Author

Choose a reason for hiding this comment

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

Good call, thanks!

Copy link
Owner Author

Choose a reason for hiding this comment

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

RESOLVED

Comment on lines 161 to 167
function getEmail(json) {
return json.val0;
}

function getUrl(json) {
return json.val1;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Consider defining your own type to store user info. That way you will avoid having to reference the generic names defined by Pair.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Apologies for the delay, I have implemented this!

Copy link
Owner Author

Choose a reason for hiding this comment

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

RESOLVED

}

function loginHtml(loginUrl) {
return "<p>Login <a href=\"" + loginUrl + "\">here</a>.";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe use a template literal?

Copy link
Owner Author

Choose a reason for hiding this comment

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

Good call, thanks!

Copy link
Owner Author

Choose a reason for hiding this comment

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

RESOLVED

Comment on lines 152 to 159
if (userEmail == 'N/A') {
const html = loginHtml(redirectUrl);
document.getElementById('login-status').innerHTML = html;
} else {
const html = logoutHtml(userEmail, redirectUrl);
document.getElementById('login-status').innerHTML = html;
document.getElementById('comments-form').style.display = "block";
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Optional: Maybe return early

Copy link
Owner Author

Choose a reason for hiding this comment

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

I've implemented this as well, thanks!

Copy link
Owner Author

Choose a reason for hiding this comment

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

RESOLVED

@tttzach tttzach force-pushed the LibrariesAuthenticationExtra branch from cef2430 to 7c6f54b Compare June 18, 2020 19:09
@tttzach tttzach assigned gbuenoandrade and unassigned tttzach Jun 22, 2020
@tttzach tttzach requested a review from gbuenoandrade June 22, 2020 14:43

package com.google.sps.servlets;

public class Pair {
Copy link
Collaborator

Choose a reason for hiding this comment

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

It doesn't really make sense to call this "Pair". A pair is a particular data structure with a generic "first" and "second" member (or something similar).

This is just a specific class for storing login information, and it should just be called LoginInfo or something.

Also, please add javadoc-style comments for the class and all public members, including the constructor.

Copy link
Owner Author

@tttzach tttzach Jun 23, 2020

Choose a reason for hiding this comment

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

Yeah, I agree especially now that's a custom class there's no reason to keep the name as Pair. I'll change it!
Ohhh I just found out what javadoc comments are. I deleted them throughout my project because I thought \** looked horrible and didn't add much value. I'll definitely pull a new request for this because I'd have to change this for all the files. #59

Copy link
Owner Author

Choose a reason for hiding this comment

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

RESOLVED #59

}
String loginUrl = userService.createLoginURL(redirectUrl);
Pair userInfo = new Pair("N/A", loginUrl);
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's generally a bad idea to use special values like "N/A".

  • It's easy to make a mistake and forget to check for the special value.
  • It's easy to change the special value and forget to update all clients.
  • It's possible that the use of the field will change in the future, and "N/A" may become a possible real value.

It's better to just add another field that holds a boolean to indicate that the user is logged in or not. The documentation on the email field should say that it should be empty when the user is not logged in.

Copy link
Owner Author

Choose a reason for hiding this comment

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

@antmar I agree, having the custom class also makes this easy to do. Just a small consideration, I've altered it such that the constructor has the following function signature: UserInfo(String email, String url, boolean loggedIn). However, if loggedIn = false then I am passing in "" to email. Is there a way to set optional parameters easily like in C++ or Python? Otherwise, would it be wise to overload this function and have one that doesn't require email as a parameter?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Another option is to create separate static factory methods for the loggedIn and loggedOut case.

  • loggedIn(String email, String url)
  • loggedOut(String url)

For details about factory methods, see Item #1 in "Effective Java 3rd Ed."

Copy link
Owner Author

Choose a reason for hiding this comment

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

I like this idea, thanks! I've added it. Great reference to the book too.

Copy link
Owner Author

Choose a reason for hiding this comment

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

RESOLVED


Pair(String email, String url) {
this.email = email;
this.url = url;
Copy link
Collaborator

Choose a reason for hiding this comment

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

"url" is a bit too generic. What does the URL point to? I suggest either:

  • Use a separate field for login URL and logout URL (only set one of them)
  • Call this something like "loginOrLogoutUrl".

Copy link
Owner Author

Choose a reason for hiding this comment

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

Good call, thanks!

Copy link
Owner Author

Choose a reason for hiding this comment

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

RESOLVED


function getUrl(json) {
return json["url"];
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think these helpers add any clarity. You can just access the property directly on the json object.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Yeah, I agree. I've removed them, thanks!

Copy link
Owner Author

Choose a reason for hiding this comment

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

RESOLVED

@antmar antmar assigned tttzach and unassigned antmar Jun 22, 2020
@gbuenoandrade gbuenoandrade removed their assignment Jun 22, 2020
@tttzach tttzach requested a review from antmar June 23, 2020 18:41
@tttzach tttzach assigned antmar and gbuenoandrade and unassigned tttzach Jun 23, 2020
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;

public final class JsonUtil {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Public classes and methods should have comments.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Thanks! Added the relevant javadoc-style comments for this class. Will go back to the other classes unrelated to this PR here #59

Copy link
Owner Author

Choose a reason for hiding this comment

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

RESOLVED

}
String loginUrl = userService.createLoginURL(redirectUrl);
Pair userInfo = new Pair("N/A", loginUrl);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Another option is to create separate static factory methods for the loggedIn and loggedOut case.

  • loggedIn(String email, String url)
  • loggedOut(String url)

For details about factory methods, see Item #1 in "Effective Java 3rd Ed."

@antmar antmar assigned tttzach and unassigned antmar Jun 23, 2020
@tttzach tttzach merged commit 810c44b into master Jun 23, 2020
* @param email
* @param logoutUrl
*/
public void loggedIn(String email, String logoutUrl) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

A standard static factory method would have a signature like this:

  public static UserInfo loggedIn(String email, String logoutUrl)

The key is that the method would create and initialize the object at the same time. You don't want users of your class to create uninitialized objects. Ideally, you would make the constructor private so that users of the class have to use your factory methods.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Thanks for the clarification - I did not fully understand why the methods had to be static. I have a better idea of what this means now after reviewing your comment and Austin's code on the prototype. I will change this in a new pull request.

Copy link
Owner Author

Choose a reason for hiding this comment

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

RESOLVED #60

@tttzach tttzach mentioned this pull request Jul 6, 2020
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