public override void DemandMutation(object entity, MutationType type, string path, object value, ISecurityContext context) { var lot = entity as Lot; if (lot.DbId == 0) { throw new SecurityException("Unclaimed lots cannot be mutated"); } var roomies = lot.Lot_RoommateVec; switch (path) { //Owner only case "Lot_Description": context.DemandAvatar(lot.Lot_LeaderID, AvatarPermissions.WRITE); var desc = value as string; if (desc != null && desc.Length > 500) { throw new Exception("Description too long!"); } break; case "Lot_Name": context.DemandAvatar(lot.Lot_LeaderID, AvatarPermissions.WRITE); if (!GlobalRealestate.ValidateLotName((string)value)) { throw new Exception("Invalid lot name"); } //Lot_Name is a special case, it has to be unique so we have to hit the db in the security check //for this mutation. TryChangeLotName(lot, (string)value); break; case "Lot_Category": context.DemandAvatar(lot.Lot_LeaderID, AvatarPermissions.WRITE); if (lot.Lot_IsOnline) { throw new SecurityException("Lot must be offline to change category!"); } //7 days if (((Epoch.Now - lot.Lot_LastCatChange) / (60 * 60)) < 168) { throw new SecurityException("You must wait 7 days to change your lot category again"); } break; case "Lot_SkillGamemode": context.DemandAvatar(lot.Lot_LeaderID, AvatarPermissions.WRITE); var svalue = (uint)value; uint minSkill; if (!SkillGameplayCategory.TryGetValue((LotCategory)lot.Lot_Category, out minSkill)) { minSkill = 0; } if (Math.Min(2, Math.Max(minSkill, svalue)) != svalue) { throw new SecurityException("Invalid gamemode for this category."); } if (lot.Lot_IsOnline) { throw new SecurityException("Lot must be offline to change skill mode!"); } break; //roommate only case "Lot_Thumbnail": context.DemandAvatars(roomies, AvatarPermissions.WRITE); //TODO: needs to be generic data, png, size 288x288, less than 1MB break; case "Lot_IsOnline": case "Lot_NumOccupants": case "Lot_RoommateVec": case "Lot_SpotLightText": context.DemandInternalSystem(); break; case "Lot_LotAdmitInfo.LotAdmitInfo_AdmitList": case "Lot_LotAdmitInfo.LotAdmitInfo_BanList": context.DemandAvatars(roomies, AvatarPermissions.WRITE); int atype = (path == "Lot_LotAdmitInfo.LotAdmitInfo_AdmitList") ? 0 : 1; using (var db = DAFactory.Get()) { //need to check db constraints switch (type) { case MutationType.ARRAY_REMOVE_ITEM: //Remove bookmark at index value var removedAva = (uint)value; db.LotAdmit.Delete(new DbLotAdmit { lot_id = (int)lot.DbId, avatar_id = removedAva, admit_type = (byte)atype }); break; case MutationType.ARRAY_SET_ITEM: //Add a new bookmark var newAva = (uint)value; db.LotAdmit.Create(new DbLotAdmit { lot_id = (int)lot.DbId, avatar_id = newAva, admit_type = (byte)atype }); break; } } break; case "Lot_LotAdmitInfo.LotAdmitInfo_AdmitMode": context.DemandAvatars(roomies, AvatarPermissions.WRITE); //can only set valid values var mode = (byte)value; if (mode < 0 || mode > 3) { throw new Exception("Invalid admit mode!"); } break; default: throw new SecurityException("Field: " + path + " may not be mutated by users"); } }