예제 #1
0
        private RealmDto MakeDto(Realm r, bool details = false)
        {
            var result = new RealmDto
            {
                Name     = r.Name,
                Owner    = r.Owner.Name,
                Uri      = Url.Link("GetRealmByName", new { realmName = r.Name }),
                Compiler = MakeDto(r.Factory),
                Privacy  = r.PrivacyLevel,
            };

            if (details)
            {
                result.Runtime = new RuntimeOptionsDto {
                    Platform = "Glulx",
                };
                result.ManifestUri = Url.Link("GetRealmAssetManifest", new { realmName = r.Name });
                result.Acl         = Array.ConvertAll(r.AccessList, e => new RealmAclEntryDto {
                    User = e.Player.Name, Access = e.Level
                });
            }

            return(result);
        }
예제 #2
0
        public async Task <IHttpActionResult> PostNewRealmAsync(RealmDto newRealm)
        {
            // verify permission
            if (!Request.CheckAccess(GunchoResources.RealmActions.Create, GunchoResources.Realm, newRealm.Name))
            {
                return(Forbidden());
            }

            // fill in defaults
            if (newRealm.Compiler == null)
            {
                newRealm.Compiler = new CompilerOptionsDto()
                {
                    Language = config.DefaultCompilerLanguage,
                    Version  = config.DefaultCompilerVersion,
                };
            }

            newRealm.Owner = User.Identity.Name;

            // validate request
            var factory = realmsService.GetRealmFactories().SingleOrDefault(f => CompilerEqualsFactory(newRealm.Compiler, f));

            if (factory == null)
            {
                ModelState.AddModelError("Compiler", "Invalid compiler settings.");
            }

            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            if (realmsService.GetRealmByName(newRealm.Name) != null)
            {
                return(Conflict());
            }

            // create the realm
            var realm = await realmsService.CreateRealmAsync(playersService.GetPlayerByName(User.Identity.Name), newRealm.Name, factory);

            if (realm == null)
            {
                // that's weird!
                if (realmsService.GetRealmByName(newRealm.Name) != null)
                {
                    return(Conflict());
                }
                else
                {
                    return(BadRequest(ModelState));
                }
            }

            // invoke the PUT handler to update any other settings
            var innerResult = (await PutRealmByNameAsync(newRealm.Name, newRealm)) as OkNegotiatedContentResult <RealmDto>;

            if (innerResult != null)
            {
                // TODO: if PUT failed, delete the realm and return an error
                return(Created(Url.Link("GetRealmByName", new { realmName = newRealm.Name }), innerResult.Content));
            }

            innerResult = GetRealmByName(newRealm.Name) as OkNegotiatedContentResult <RealmDto>;
            return(Created(Url.Link("GetRealmByName", new { realmName = newRealm.Name }), GetRealmByName(newRealm.Name)));
        }
예제 #3
0
        public async Task <IHttpActionResult> PutRealmByNameAsync(string realmName, RealmDto newSettings)
        {
            // TODO: use ETags for concurrency control

            var realm = realmsService.GetRealmByName(realmName);

            if (realm == null)
            {
                return(NotFound());
            }

            if (!Request.CheckAccess(GunchoResources.RealmActions.Edit, GunchoResources.Realm, realmName))
            {
                return(Forbidden());
            }

            var checks  = new Queue <Check <Realm> >();
            var updates = new Queue <Action <Realm> >();

            // TODO: don't modify Realm objects, do everything through service methods (see ProfilesController)

            if (newSettings.Name != null && newSettings.Name != realm.Name)
            {
                checks.Enqueue(new Check <Realm>(
                                   r => realmsService.IsValidNameChange(r.Name, newSettings.Name),
                                   "Name", "Invalid realm name."));
                checks.Enqueue(new Check <Realm>(
                                   r => Request.CheckAccess(
                                       GunchoResources.RealmActions.Edit,
                                       GunchoResources.Realm, r.Name,
                                       GunchoResources.Field, GunchoResources.RealmFields.Name),
                                   "Name", "Permission denied."));
                updates.Enqueue(r => r.Name = newSettings.Name);
            }

            if (newSettings.Owner != realm.Owner.Name)
            {
                checks.Enqueue(new Check <Realm>(
                                   r => Request.CheckAccess(
                                       GunchoResources.RealmActions.Edit,
                                       GunchoResources.Realm, r.Name,
                                       GunchoResources.Field, GunchoResources.RealmFields.Owner),
                                   "Owner", "Permission denied."));
                checks.Enqueue(new Check <Realm>(
                                   r => playersService.GetPlayerByName(newSettings.Owner) != null,
                                   "Owner", "No such player."));
                updates.Enqueue(r => r.Owner = playersService.GetPlayerByName(newSettings.Owner) ?? r.Owner);
            }

            // acl
            if (newSettings.Acl != null && !AclEqualsDto(realm.AccessList, newSettings.Acl))
            {
                checks.Enqueue(new Check <Realm>(
                                   r => Request.CheckAccess(
                                       GunchoResources.RealmActions.Edit,
                                       GunchoResources.Realm, r.Name,
                                       GunchoResources.Field, GunchoResources.RealmFields.Acl),
                                   "Acl", "Permission denied."));
                checks.Enqueue(new Check <Realm>(
                                   r => newSettings.Acl.All(e => playersService.GetPlayerByName(e.User) != null),
                                   "Acl", "No such player(s)."));
                updates.Enqueue(r =>
                {
                    try
                    {
                        r.AccessList = DtoToAcl(newSettings.Acl);
                    }
                    catch (InvalidOperationException)
                    {
                        // don't change ACL if some player names are invalid
                    }
                });
            }

            // privacy
            if (newSettings.Privacy != realm.PrivacyLevel)
            {
                checks.Enqueue(new Check <Realm>(
                                   r => Request.CheckAccess(
                                       GunchoResources.RealmActions.Edit,
                                       GunchoResources.Realm, r.Name,
                                       GunchoResources.Field, GunchoResources.RealmFields.Privacy),
                                   "Privacy", "Permission denied."));
                updates.Enqueue(r => r.PrivacyLevel = newSettings.Privacy);
            }

            // compiler
            if (!CompilerEqualsFactory(newSettings.Compiler, realm.Factory))
            {
                checks.Enqueue(new Check <Realm>(
                                   r => realmsService.GetRealmFactories().Count(f => CompilerEqualsFactory(newSettings.Compiler, f)) == 1,
                                   "Compiler", "Invalid compiler settings."));
                updates.Enqueue(r =>
                                r.Factory = realmsService.GetRealmFactories().Single(f => CompilerEqualsFactory(newSettings.Compiler, f)));

                // TODO: recompile realm if compiler setting is changed
            }

            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            var result = await realmsService.TransactionalUpdateAsync(
                realm,
                r =>
            {
                bool ok = true;

                foreach (var check in checks)
                {
                    if (!check.CheckFunc(r))
                    {
                        ok = false;
                        ModelState.AddModelError(check.ModelKey, check.ErrorMsg);
                    }
                }

                if (!ok)
                {
                    return(false);
                }

                foreach (var update in updates)
                {
                    update(r);
                }

                return(true);
            });

            if (result == false)
            {
                return(BadRequest(ModelState));
            }

            return(GetRealmByName(realmName));
        }