/* emailListCustom.java Custom plug-in for managing fields in the email list object type. Created: 16 February 1999 Module By: Jonathan Abbey, jonabbey@arlut.utexas.edu ----------------------------------------------------------------------- Ganymede Directory Management System Copyright (C) 1996-2013 The University of Texas at Austin Ganymede is a registered trademark of The University of Texas at Austin Contact information Web site: http://www.arlut.utexas.edu/gash2 Author Email: ganymede_author@arlut.utexas.edu Email mailing list: ganymede@arlut.utexas.edu US Mail: Computer Science Division Applied Research Laboratories The University of Texas at Austin PO Box 8029, Austin TX 78713-8029 Telephone: (512) 835-3200 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package arlut.csd.ganymede.gasharl; import java.util.Vector; import arlut.csd.Util.VectorUtils; import arlut.csd.ganymede.common.Invid; import arlut.csd.ganymede.common.NotLoggedInException; import arlut.csd.ganymede.common.Query; import arlut.csd.ganymede.common.QueryDataNode; import arlut.csd.ganymede.common.QueryNode; import arlut.csd.ganymede.common.QueryNotNode; import arlut.csd.ganymede.common.QueryResult; import arlut.csd.ganymede.common.ReturnVal; import arlut.csd.ganymede.common.SchemaConstants; import arlut.csd.ganymede.server.DBEditObject; import arlut.csd.ganymede.server.DBEditSet; import arlut.csd.ganymede.server.DBField; import arlut.csd.ganymede.server.DBObject; import arlut.csd.ganymede.server.DBObjectBase; import arlut.csd.ganymede.server.Ganymede; import arlut.csd.ganymede.server.GanymedeSession; import arlut.csd.ganymede.server.InvidDBField; import arlut.csd.ganymede.server.StringDBField; /*------------------------------------------------------------------------------ class emailListCustom ------------------------------------------------------------------------------*/ /** * Custom plug-in for managing fields in the email list object type. */ public class emailListCustom extends DBEditObject implements SchemaConstants, emailListSchema { private QueryResult membersChoice = null; /* -- */ /** * * Customization Constructor * */ public emailListCustom(DBObjectBase objectBase) { super(objectBase); } /** * * Create new object constructor * */ public emailListCustom(DBObjectBase objectBase, Invid invid, DBEditSet editset) { super(objectBase, invid, editset); } /** * * Check-out constructor, used by DBObject.createShadow() * to pull out an object for editing. * */ public emailListCustom(DBObject original, DBEditSet editset) { super(original, editset); } /** * <p>This method is used to provide a hook to allow different * objects to generate different labels for a given object based on * their perspective. This is used to sort of hackishly simulate a * relational-type capability for the purposes of viewing * backlinks.</p> * * <p>See the automounter map and NFS volume DBEditObject subclasses * for how this is to be used, if you have them.</p> */ @Override public String lookupLabel(DBObject object) { if (object.getTypeID() == SchemaConstants.UserBase) { String fullName = (String) object.getFieldValueLocal(userSchema.FULLNAME); String name = (String) object.getFieldValueLocal(userSchema.USERNAME); if (fullName != null && name != null) { return name + " (" + fullName + ")"; } } // mark email lists if (object.getTypeID() == emailListSchema.BASE) { return super.lookupLabel(object) + " (email list)"; } // and groups if (object.getTypeID() == groupSchema.BASE) { return super.lookupLabel(object) + " (group)"; } // and user netgroups if (object.getTypeID() == userNetgroupSchema.BASE) { return super.lookupLabel(object) + " (user netgroup)"; } // mark email redirects if (object.getTypeID() == emailRedirectSchema.BASE) { Vector<Invid> addresses = (Vector<Invid>) object.getFieldValuesLocal(emailListSchema.MEMBERS); return super.lookupLabel(object) + " (" + VectorUtils.vectorString(addresses) + ")"; } return super.lookupLabel(object); } /** * <p>This method returns a key that can be used by the client to * cache the value returned by choices(). If the client already has * the key cached on the client side, it can provide the choice list * from its cache rather than calling choices() on this object * again.</p> * * <p>If there is no caching key, this method will return null.</p> */ @Override public Object obtainChoicesKey(DBField field) { // we don't want the members field to be cached, since we are // amalgamating several kinds of things into one invid field. if (field.getID() == MEMBERS) { return null; } return super.obtainChoicesKey(field); } /** * <p>This method provides a hook that can be used to generate * choice lists for invid and string fields that provide such. * String and Invid DBFields will call their owner's * obtainChoiceList() method to get a list of valid choices.</p> * * <p>This method will provide a reasonable default for targetted * invid fields.</p> */ @Override public QueryResult obtainChoiceList(DBField field) throws NotLoggedInException { if (field.getID() != emailListSchema.MEMBERS) { return super.obtainChoiceList(field); } if (membersChoice == null) { // we want to present a list of all users, mail groups besides // this one, and external mail aliases (email addresses that // have local aliases in ARL's mail system) as valid choices // for the MEMBERS field. Query query1 = new Query(SchemaConstants.UserBase, null, false); Query query2 = new Query(emailRedirectSchema.BASE, null, false); QueryNode root3 = new QueryNotNode(new QueryDataNode((short) -2, QueryDataNode.EQUALS, this.getInvid())); Query query3 = new Query(emailListSchema.BASE, root3, false); // we also need to union in user netgroups and account groups // that have the 'Can Receive Email' box checked. // first groups QueryNode root4 = new QueryDataNode(groupSchema.EMAILOK, QueryDataNode.DEFINED, null); Query query4 = new Query(groupSchema.BASE, root4, false); // and then user netgroups QueryNode root5 = new QueryDataNode(userNetgroupSchema.EMAILOK, QueryDataNode.DEFINED, null); Query query5 = new Query(userNetgroupSchema.BASE, root4, false); QueryResult result = editset.getDBSession().getGSession().query(query1, this); result.append(editset.getDBSession().getGSession().query(query2, this)); result.append(editset.getDBSession().getGSession().query(query3, this)); result.append(editset.getDBSession().getGSession().query(query4, this)); result.append(editset.getDBSession().getGSession().query(query5, this)); membersChoice = result; } return membersChoice; } /** * <p>This method is used to control whether or not it is acceptable to * make a link to the given field in this * {@link arlut.csd.ganymede.server.DBObject DBObject} type when the * user only has editing access for the source * {@link arlut.csd.ganymede.server.InvidDBField InvidDBField} and not * the target.</p> * * <p>This version of anonymousLinkOK takes additional parameters * to allow an object type to decide that it does or does not want * to allow a link based on what field of what object wants to link * to it.</P> * * <p>By default, the 3 variants of the DBEditObject anonymousLinkOK() * method are chained together, so that the customizer can choose * which level of detail he is interested in. * {@link arlut.csd.ganymede.server.InvidDBField InvidDBField}'s * {@link arlut.csd.ganymede.server.InvidDBField#bind(arlut.csd.ganymede.common.Invid,arlut.csd.ganymede.common.Invid,boolean) bind()} * method calls this version. This version calls the three parameter * version, which calls the two parameter version, which returns * false by default. Customizers can implement any of the three * versions, but unless you maintain the version chaining yourself, * there's no point to implementing more than one of them.</P> * * <p><b>*PSEUDOSTATIC*</b></p> * * @param targetObject The object that the link is to be created in * @param targetFieldID The field that the link is to be created in * @param sourceObject The object on the other side of the proposed link * @param sourceFieldID The field on the other side of the proposed link * @param gsession Who is trying to do this linking? */ @Override public boolean anonymousLinkOK(DBObject targetObject, short targetFieldID, DBObject sourceObject, short sourceFieldID, GanymedeSession gsession) { // if someone tries to put this list in another email list, let // them. if ((targetFieldID == SchemaConstants.BackLinksField) && (sourceObject.getTypeID() == emailListSchema.BASE) && (sourceFieldID == emailListSchema.MEMBERS)) { return true; } // the default anonymousLinkOK() method returns false return super.anonymousLinkOK(targetObject, targetFieldID, sourceObject, sourceFieldID, gsession); } /** * <p>Customization method to control whether a specified field * is required to be defined at commit time for a given object.</p> * * <p>To be overridden in DBEditObject subclasses.</p> * * <p>Note that this method will not be called if the controlling * GanymedeSession's enableOversight is turned off, as in * bulk loading.</p> * * <p><b>*PSEUDOSTATIC*</b></p> */ @Override public boolean fieldRequired(DBObject object, short fieldid) { // the email list name is required if (fieldid == emailListSchema.LISTNAME) { return true; } return super.fieldRequired(object, fieldid); } }