package com.rectang.xsm.pages.admin; import com.rectang.xsm.pages.EditProfile; import com.rectang.xsm.pages.XSMPage; import com.rectang.xsm.pages.Secure; import com.rectang.xsm.AccessControl; import com.rectang.xsm.UserData; import com.rectang.xsm.XSM; import com.rectang.xsm.site.Visitor; import com.rectang.xsm.util.EmailUtils; import com.rectang.xsm.wicket.DetachableUserDataModel; import com.rectang.xsm.io.RemoteDocument; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.markup.html.link.BookmarkablePageLink; import org.apache.wicket.markup.html.link.Link; import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.image.Image; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.model.Model; import org.apache.wicket.model.IModel; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.DefaultDataTable; import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn; import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider; import org.apache.wicket.PageParameters; import org.apache.wicket.ResourceReference; import java.util.*; import java.io.File; /** * Page for managing the site's users (and groups in the future) * * TODO add confirmation for deleting users * TODO either add confirmation for, or disallow a user from deleting or removing admin from himself * * @author Andrew Williams * @version $Id: Users.java 816 2010-05-30 14:02:03Z andy $ * @since 2.0 */ public class Users extends XSMPage implements Secure { public Users( PageParameters parameters ) { super( parameters ); } public int getLevel() { return AccessControl.MANAGER; } public void layout() { super.layout(); UserData user = getXSMSession().getUser(); final com.rectang.xsm.site.Site site = getXSMSession().getSite(); List columns = new ArrayList(); columns.add( new PropertyColumn( new Model( "Username" ), "username", "username" ) ); columns.add( new PropertyColumn( new Model( "Name" ), "name" ) ); columns.add( new AbstractColumn( new Model( "Status" ) ) { public void populateItem( Item item, String componentId, IModel model ) { UserData user = (UserData) model.getObject(); String status = ""; if ( user.isXSMAdmin() ) { status = "XSM Admin"; } else if ( user.isSiteAdmin() ) { status = "Site Admin"; } else if ( user.isSiteEditor() ) { status = "Site Editor"; } item.add( new Label( componentId, status ) ); } } ); columns.add( new PropertyColumn( new Model( "Email" ), "email" ) ); columns.add( new PropertyColumn( new Model( "Last Login" ), "lastLogin" ) ); columns.add( new AbstractColumn( new Model( "Actions" ) ) { public void populateItem( Item item, String componentId, IModel model ) { item.add( new UsersActionPanel( componentId, ((UserData) model.getObject()) ) ); } } ); columns.add( new PropertyColumn( new Model( "Notes" ), "note" ) ); add( new DefaultDataTable( "users", columns, new UserDataProvider( site ), 10 ) ); // Add a permissions table too columns = new ArrayList(); columns.add( new PropertyColumn( new Model( "Username" ), "username", "username" ) ); columns.add( new PropertyColumn( new Model( "Name" ), "name" ) ); columns.add( new AbstractColumn( new Model( "Site Admin" ) ) { public void populateItem( Item item, String componentId, IModel model ) { UserData user = (UserData) model.getObject(); item.add( new PermissionPanel( componentId, user, "siteAdmin" ) ); } } ); columns.add( new AbstractColumn( new Model( "Site Editor" ) ) { public void populateItem( Item item, String componentId, IModel model ) { UserData user = (UserData) model.getObject(); item.add( new PermissionPanel( componentId, user, "siteEditor" ) ); } } ); add( new DefaultDataTable( "permissions", columns, new UserDataProvider( site ), 10 ) ); columns = new ArrayList(); columns.add( new PropertyColumn( new Model( "Username" ), "username", "username" ) ); columns.add( new AbstractColumn( new Model( "Actions" ) ) { public void populateItem( Item item, String componentId, IModel model ) { item.add( new VisitorActionPanel( componentId, ((Visitor) model.getObject()), site ) ); } } ); add( new DefaultDataTable( "visitors", columns, new VisitorDataProvider( site ), 10 ) .setVisible( site.getTechnologies().contains( "apache" ) ) ); } public static List getUserList( com.rectang.xsm.site.Site site ) { return getUserList( site, true ); } public static List getUserList( com.rectang.xsm.site.Site site, boolean listXSMAdmins ) { Vector users = new Vector(); File[] userFiles = (RemoteDocument.getDoc( site, "/members", false )).listFiles(); for ( int i = 0; i < userFiles.length; i++ ) { String next = userFiles[i].getName(); if ( next.endsWith( ".xml" ) ) { String username = next.substring( 0, next.length() - 4 ); users.add( new UserData( username, site, false ) ); } } if ( listXSMAdmins ) { /* list XSM admins too */ File[] adminFiles = new File( XSM.getConfig().getDataDir(), "admins" ).listFiles(); if ( adminFiles != null ) { for ( int i = 0; i < adminFiles.length; i++ ) { String next = adminFiles[i].getName(); if ( next.endsWith( ".xml" ) ) { String username = next.substring( 0, next.length() - 4 ); users.add( new UserData( username, site, false ) ); } } } } return users; } class UsersActionPanel extends Panel { private UserData user; public UsersActionPanel( String id, final UserData user ) { super( id ); this.user = user; String username = user.getUsername(); boolean iAmXSMAdmin = getXSMSession().getUser().isXSMAdmin(); WebMarkupContainer component; PageParameters params = new PageParameters(); params.add( "username", username ); // don't allow non-XSMAdmins to edit XSMAdmin accounts BookmarkablePageLink edit = new BookmarkablePageLink( "edit", EditProfile.class, params ); if ( user.isXSMAdmin() && !iAmXSMAdmin ) { edit.setVisible( false ); } add( edit ); add( component = new Link( "delete" ) { public void onClick() { if ( user.isXSMAdmin() ) { warn( "Cannot delete an XSM admin user" ); return; } // TODO add a confirmation message RemoteDocument userFile = RemoteDocument.getDoc( user.getSite(), "/members/" + user.getUsername(), true ); if ( userFile.delete() ) { if ( user.getSite().getTechnologies().contains( "apache" ) ) { user.getSite().removeVisitor( new Visitor( user.getUsername() ) ); } info( "User " + user.getUsername() + " has been deleted" ); } else { warn( "Could not delete user " + user.getUsername() ); } } } ); component.add( new Image( "delete-icon", new ResourceReference( XSM.class, "icons/edit-delete.png" ) ) ); // don't allow deletion of XSM Admins by non-XSMAdmins if ( user.isXSMAdmin() && !iAmXSMAdmin ) { component.setVisible( false ); } add( component = new Link( "reset" ) { public void onClick() { RemoteDocument doc = RemoteDocument.getDoc( user.getSite(), "/members/" + user.getUsername(), true ); if ( !doc.exists() ) { warn( "Cannot reset non-existant user " + user.getUsername() + "." ); } else if ( user.isXSMAdmin() ) { warn( "Cannot reset an XSM admin user" ); } else { UserData userData = new UserData( user.getUsername(), user.getSite(), false ); String email = userData.getEmail(); String newPassword = com.rectang.xsm.util.StringUtils.createPassword(); userData.setPassword( newPassword ); if ( userData.save() ) { if ( user.getSite().getTechnologies().contains( "apache" ) ) { user.getSite().setVisitor( new Visitor( user.getUsername(), newPassword ) ); } if ( email != null && !email.equals( "" ) ) { String subject = "Your XSM password for site " + user.getSite().getId() + " has been reset"; String body = "The XSM password for user " + user.getUsername() + " in site " + user.getSite().getId() + " has been reset.\n\n" + "Your new password is " + newPassword + " please change it after logging in\n" + "Should you have any further problems please contact your site administrator\n"; EmailUtils.emailTo( subject, body, email ); info( "Reset user " + user.getUsername() + "'s password" ); } else { info( "Reset user " + user.getUsername() + "'s password to " + newPassword + ".<br />\n" + " Unfortunately their email address is blank so please" + " let them know!" ); } } } } } ); component.add( new Image( "reset-icon", new ResourceReference( XSM.class, "icons/view-refresh.png" ) ) ); // don't allow resetting of an XSM Admin's passwords by non-XSMAdmins if ( user.isXSMAdmin() && !iAmXSMAdmin ) { component.setVisible( false ); } } } class PermissionPanel extends Panel { public PermissionPanel( String id, final UserData user, final String property ) { super( id ); CheckBox permission; add( permission = new CheckBox( "permission", new PropertyModel( user, property ) ) { // setting of the boolean on the user object will save the site data automatically :) protected boolean wantOnSelectionChangedNotifications() { return true; } } ); // XSM Admin accounts cannot have permissions switched off if ( user.isXSMAdmin() ) { permission.setEnabled( false ); } } } class VisitorActionPanel extends Panel { private Visitor visitor; public VisitorActionPanel( String id, final Visitor visitor, final com.rectang.xsm.site.Site site ) { super( id ); this.visitor = visitor; final String username = visitor.getUsername(); WebMarkupContainer component; PageParameters params = new PageParameters(); params.add( "username", username ); add( component = new Link( "delete" ) { public void onClick() { // TODO add a confirmation message site.removeVisitor( visitor ); info( "Visitor account " + visitor.getUsername() + " has been deleted" ); } } ); component.add( new Image( "delete-icon", new ResourceReference( XSM.class, "icons/edit-delete.png" ) ) ); add( component = new Link( "reset" ) { public void onClick() { // TODO set password command String newPassword = com.rectang.xsm.util.StringUtils.createPassword(); site.setVisitor( new Visitor( username, newPassword ) ); info( "Reset visitor " + visitor.getUsername() + "'s password to " + newPassword + ". Please pass this information to them!" ); } } ); component.add( new Image( "reset-icon", new ResourceReference( XSM.class, "icons/view-refresh.png" ) ) ); } } } class UserDataProvider extends SortableDataProvider { private com.rectang.xsm.site.Site site; public UserDataProvider( com.rectang.xsm.site.Site site ) { this.site = site; } public Iterator iterator( int from, int to ) { List userList = Users.getUserList( site ); Collections.sort( userList ); if ( getSort() != null && getSort().isAscending() ) { Collections.reverse( userList ); } return userList.subList( from, from + to ).iterator(); } public int size() { return Users.getUserList( site ).size(); } public IModel model( Object object ) { return new DetachableUserDataModel( (UserData) object ); } } class VisitorDataProvider extends SortableDataProvider { private com.rectang.xsm.site.Site site; public VisitorDataProvider( com.rectang.xsm.site.Site site ) { this.site = site; } public Iterator iterator( int from, int to ) { List visitorList = site.getVisitors(); Collections.sort( visitorList ); if ( getSort() != null && getSort().isAscending() ) { Collections.reverse( visitorList ); } return visitorList.subList( from, from + to ).iterator(); } public int size() { return site.getVisitors().size(); } public IModel model( Object object ) { return new Model( (Visitor) object );//new DetachableVisitorModel((Visitor) object); } }