package gotnames.web.st;
import gotnames.Utils;
import gotnames.dm.KTrans;
import gotnames.dm.ProfilePicture;
import gotnames.dm.ProfilePictureData;
import gotnames.dm.QueryBuilder;
import gotnames.dm.User;
import gotnames.dm.User.Gender;
import gotnames.email.InviteEmail;
import gotnames.web.GotNamesServlet.UserAuthenticator;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.mail.MessagingException;
import com.medallia.spider.DropdownElement;
import com.medallia.tiny.CollUtils;
import com.medallia.tiny.Empty;
import com.medallia.tiny.Funcs;
import com.medallia.tiny.Predicate;
import com.medallia.tiny.Predicate.Predicates;
/**
* Task only available to users with {@link User#isAdmin()}. Allows adding new
* users, editing all users in the group and also {@link DownloadArchiveTask}
* and {@link UploadArchiveTask}.
*/
public class AdminTask extends GotNamesTask {
@Input interface Params {
String email();
String firstName();
String lastName();
Gender gender();
boolean admin();
boolean disableEmail();
byte[] profilePicture();
}
@Output interface Values {
V<List<DropdownElement>> GENDER_OPTIONS = v();
V<Collection<User>> USERS = v();
}
PostAction action(final User user, final Params p, DynamicInput di, PersistenceManager pm, UserAuthenticator userAuthenticator) {
if (!user.isAdmin())
return redirectToTask(GuessNamesTask.class);
final ProfilePictureData profilePicture = ProfilePictureData.getProfilePicture(p.profilePicture());
final String email = p.email();
if (email != null) {
// Check if the email is already in use
User existingUser = User.getByEmail(pm, email);
if (existingUser != null)
return rawStringUtf8("Email address is already in use by user '" + existingUser.getFullName() + "'");
User newUser = new KTrans<User>(pm) {
@Override protected User call() {
User u = User.newUser(user.getGroupKey());
u.setEmail(email);
u.setFirstName(Utils.notNull(p.firstName(), "First name is required"));
u.setLastName(Utils.notNull(p.lastName(), "Last name is required"));
u.setGender(Utils.notNull(p.gender(), "Gender is required"));
u.setAdmin(p.admin());
u.setDisableEmail(p.disableEmail());
if (profilePicture != null)
u.setProfilePictureInfo(profilePicture);
pm.makePersistent(u);
return u;
}
}.go();
if (!newUser.isDisableEmail()) {
try {
InviteEmail.sendTo(newUser, true);
} catch (IOException e) {
return rawStringUtf8("Failed to send invite email to new user: " + e.getMessage());
} catch (MessagingException e) {
return rawStringUtf8("Failed to send invite email to new user: " + e.getMessage());
}
}
}
ProfilePicture.saveProfilePicture(user, pm, profilePicture);
Query q = pm.newQuery(User.class);
q.setFilter("groupKey == " + user.getGroupKey());
q.setOrdering("firstName ASC, lastName ASC");
Collection<User> users;
try {
users = updateUsers(user, Utils.<Collection<User>>cast(q.execute()), di, pm, userAuthenticator);
} catch (IllegalArgumentException e) {
return rawStringUtf8(e.getMessage());
}
attr(Values.GENDER_OPTIONS, DropdownElement.fromEnum(Gender.class, null));
attr(Values.USERS, users);
return null;
}
private Collection<User> updateUsers(final User loggedInUser, final Collection<User> allUsers, final DynamicInput di, PersistenceManager pm, final UserAuthenticator userAuthenticator) {
final List<User> deletedUsers = CollUtils.filteredCopy(allUsers, new Predicate<User>() {
@Override public boolean accept(User u) {
return di.getInput(u.getKey() + "_delete", Boolean.TYPE);
}
});
List<Long> deletedUserKeys = Funcs.map(deletedUsers, User.KEY_FUNC);
final Collection<User> users = deletedUsers.isEmpty() ? allUsers : CollUtils.filteredCopy(allUsers, Predicates.not(inSet(deletedUsers)));
for (final User u : deletedUsers) {
new KTrans.Void(pm) {
@Override protected void run() {
pm.deletePersistent(u);
}
}.go();
}
for (final User u : users) {
final Long key = u.getKey();
final String email = di.getInput(key + "_email", String.class);
if (email != null) {
User newLoggedInUser = new KTrans<User>(pm) {
@Override protected User call() {
User.checkCanSetEmail(pm, u, email);
u.setEmail(email);
u.setFirstName(Utils.notNull(di.getInput(key + "_firstName", String.class), "First name is required"));
u.setLastName(Utils.notNull(di.getInput(key + "_lastName", String.class), "Last name is required"));
u.setGender(Utils.notNull(di.getInput(key + "_gender", Gender.class), "Gender is required"));
u.setAdmin(di.getInput(key + "_admin", Boolean.TYPE));
u.setDisableEmail(di.getInput(key + "_disableEmail", Boolean.TYPE));
ProfilePictureData profilePicture = ProfilePictureData.getProfilePicture(di.getInput(key + "_profilePicture", byte[].class));
if (profilePicture != null)
u.setProfilePictureInfo(profilePicture);
pm.makePersistent(u);
if (loggedInUser.getKey().equals(u.getKey())) {
// Prevent user from getting locked out
if (!u.isAdmin())
throw new IllegalArgumentException("Cannot disable admin for logged in user");
return u;
} else {
return null;
}
}
}.go();
if (di.getInput(key + "_sendInvite", Boolean.TYPE)) {
try {
InviteEmail.sendTo(u, true);
} catch (IOException e) {
throw new IllegalStateException("Failed to send invite email to " + u.getFullName() + ": " + e.getMessage());
} catch (MessagingException e) {
throw new IllegalStateException("Failed to send invite email to " + u.getFullName() + ": " + e.getMessage());
}
}
if (newLoggedInUser != null)
userAuthenticator.userUpdated(newLoggedInUser);
}
}
if (!deletedUsers.isEmpty()) {
Collection<ProfilePicture> pictures = QueryBuilder.begin(pm, ProfilePicture.class).getAllByKey("userKey", deletedUserKeys);
for (final ProfilePicture profilePicture : pictures) {
new KTrans.Void(pm) {
@Override protected void run() {
pm.deletePersistent(profilePicture);
}
}.go();
}
}
return users;
}
private static <X> Predicate<X> inSet(Collection<X> objects) {
final Set<X> set = Empty.hashSet(objects);
return new Predicate<X>() {
@Override public boolean accept(X e) {
return set.contains(e);
}
};
}
@Override public String getPageTitle() { return "Admin"; }
}