public ActionResult Save(string sql, string title, string description, int siteId, int? querySetId, bool? textResults, bool? withExecutionPlan, TargetSites? targetSites) { if (CurrentUser.IsAnonymous && !CaptchaController.CaptchaPassed(GetRemoteIP())) { return Json(new { captcha = true }); } ActionResult response = null; try { if (!ValidateTargetSites(targetSites)) { throw new ApplicationException("Invalid target sites selection"); } QuerySet querySet = null; if (querySetId.HasValue) { querySet = Current.DB.QuerySets.Get(querySetId.Value); if (querySet == null) { throw new ApplicationException("Invalid query set ID"); } } var parsedQuery = new ParsedQuery( sql, Request.Params, withExecutionPlan == true, targetSites ?? TargetSites.Current ); QueryResults results = null; Site site = GetSite(siteId); ValidateQuery(parsedQuery, site); if (title.HasValue() && title.Length > 100) { throw new ApplicationException("Title must be no more than 100 characters"); } if (description.HasValue() && description.Length > 1000) { throw new ApplicationException("Description must be no more than 1000 characters"); } var contextData = new QueryContextData { Title = title, Description = description, IsText = textResults == true, QuerySet = querySet }; var asyncResults = AsyncQueryRunner.Execute(parsedQuery, CurrentUser, site, contextData); if (asyncResults.State == AsyncQueryRunner.AsyncState.Failure) { throw asyncResults.Exception; } if (asyncResults.State == AsyncQueryRunner.AsyncState.Success || asyncResults.State == AsyncQueryRunner.AsyncState.Cancelled) { results = asyncResults.QueryResults; } else { return Json(new {running = true, job_id = asyncResults.JobId}); } response = CompleteResponse(results, parsedQuery, contextData, siteId); } catch (Exception ex) { response = TransformExecutionException(ex); } return response; }
public ActionResult Execute(int querySetId, int revisionId, int siteId, bool? textResults, bool? withExecutionPlan, TargetSites? targetSites) { if (CurrentUser.IsAnonymous && !CaptchaController.CaptchaPassed(GetRemoteIP())) { return Json(new { captcha = true }); } ActionResult response = null; try { if (!ValidateTargetSites(targetSites)) { throw new ApplicationException("Invalid target sites selection"); } QuerySet querySet = null; querySet = Current.DB.QuerySets.Get(querySetId); if (querySet == null) { throw new ApplicationException("Invalid query set ID"); } Revision revision = Current.DB.Revisions.Get(revisionId); if (revision == null) { throw new ApplicationException("Invalid revision ID"); } Query query = Current.DB.Queries.Get(revision.QueryId); var parsedQuery = new ParsedQuery( query.QueryBody, Request.Params, withExecutionPlan == true, targetSites ?? TargetSites.Current ); QueryResults results = null; Site site = GetSite(siteId); ValidateQuery(parsedQuery, site); var contextData = new QueryContextData { IsText = textResults == true, QuerySet = querySet, Revision = revision }; var asyncResults = AsyncQueryRunner.Execute(parsedQuery, CurrentUser, site, contextData); if (asyncResults.State == AsyncQueryRunner.AsyncState.Failure) { throw asyncResults.Exception; } if (asyncResults.State == AsyncQueryRunner.AsyncState.Success) { results = asyncResults.QueryResults; } else { return Json(new { running = true, job_id = asyncResults.JobId }); } response = CompleteResponse(results, parsedQuery, contextData, siteId); } catch (Exception ex) { response = TransformExecutionException(ex); } return response; }
public static AsyncResult Execute(ParsedQuery query, User user, Site site, QueryContextData context) { string userTag = user.IsAnonymous ? user.IPAddress : user.Id.ToString(); List<Task> activeTasks; running.TryGetValue(userTag, out activeTasks); if (activeTasks != null) { lock(activeTasks) { if (activeTasks.Where(t => !t.IsCompleted).Count() >= AppSettings.ConcurrentQueries) { throw new ApplicationException("Too many queries are running, you may only run " + AppSettings.ConcurrentQueries + " queries at a time"); } } } else { running.TryAdd(userTag, new List<Task>()); activeTasks = running[userTag]; } AsyncResult result = new AsyncResult { JobId = Guid.NewGuid(), State = AsyncState.Pending, ParsedQuery = query, Site = site, LastPoll = DateTime.UtcNow, QueryContextData = context }; Task task = new Task(() => { try { result.QueryResults = QueryRunner.GetResults(query, site, user, result); if (result.State == AsyncState.Pending) { result.State = AsyncState.Success; } } catch (Exception e) { result.Exception = e; result.State = AsyncState.Failure; } }); task.ContinueWith(ignore => { result.CompletionDate = DateTime.UtcNow; lock (activeTasks) { activeTasks.RemoveAll(t => t.IsCompleted); } }); result.Task = task; jobs.TryAdd(result.JobId, result); task.Start(); lock(activeTasks) { activeTasks.Add(task); } // give it some time to get results ... System.Threading.Thread.Sleep(50); return result; }
private ActionResult CompleteResponse( QueryResults results, ParsedQuery parsedQuery, QueryContextData context, int siteId ) { results = TranslateResults(parsedQuery, context.IsText, results); var query = Current.DB.Query<Query>( "SELECT * FROM Queries WHERE QueryHash = @hash", new { hash = parsedQuery.Hash } ).FirstOrDefault(); int revisionId = 0; DateTime saveTime; // We only create revisions if something actually changed. // We'll log it as an execution anyway if applicable, so the user will // still get a link in their profile, just not their own revision. if (context.Revision == null && (context.QuerySet == null || query == null || context.QuerySet.CurrentRevision == null || context.QuerySet.CurrentRevision.QueryId != query.Id)) { int queryId; if (query == null) { queryId = (int)Current.DB.Queries.Insert( new { QueryHash = parsedQuery.Hash, QueryBody = parsedQuery.Sql } ); } else { queryId = query.Id; } revisionId = (int)Current.DB.Revisions.Insert( new { QueryId = queryId, OwnerId = CurrentUser.IsAnonymous ? null : (int?)CurrentUser.Id, OwnerIP = GetRemoteIP(), CreationDate = saveTime = DateTime.UtcNow, OriginalQuerySetId = context.QuerySet != null ? context.QuerySet.Id : (int?)null } ); int querySetId; // brand new queryset if (context.QuerySet == null) { // insert it querySetId = (int)Current.DB.QuerySets.Insert(new { InitialRevisionId = revisionId, CurrentRevisionId = revisionId, context.Title, context.Description, LastActivity = DateTime.UtcNow, Votes = 0, Views = 0, Featured = false, Hidden = false, CreationDate = DateTime.UtcNow, OwnerIp = CurrentUser.IPAddress, OwnerId = CurrentUser.IsAnonymous?(int?)null:CurrentUser.Id }); Current.DB.Revisions.Update(revisionId, new { OriginalQuerySetId = querySetId }); } else if ( (CurrentUser.IsAnonymous && context.QuerySet.OwnerIp == CurrentUser.IPAddress) || context.QuerySet.OwnerId != CurrentUser.Id) { // fork it querySetId = (int)Current.DB.QuerySets.Insert(new { InitialRevisionId = context.QuerySet.InitialRevisionId, CurrentRevisionId = revisionId, context.Title, context.Description, LastActivity = DateTime.UtcNow, Votes = 0, Views = 0, Featured = false, Hidden = false, CreationDate = DateTime.UtcNow, OwnerIp = CurrentUser.IPAddress, OwnerId = CurrentUser.IsAnonymous ? (int?)null : CurrentUser.Id, ForkedQuerySetId = context.QuerySet.Id }); Current.DB.Execute(@"insert QuerySetRevisions(QuerySetId, RevisionId) select @newId, RevisionId from QuerySetRevisions where QuerySetId = @oldId", new { newId = querySetId, oldId = context.QuerySet.Id }); } else { // update it querySetId = context.QuerySet.Id; context.Title = context.Title ?? context.QuerySet.Title; context.Description = context.Description ?? context.QuerySet.Description; Current.DB.QuerySets.Update(context.QuerySet.Id, new { context.Title, context.Description, CurrentRevisionId = revisionId, LastActivity = DateTime.UtcNow}); } Current.DB.QuerySetRevisions.Insert(new { QuerySetId = querySetId, RevisionId = revisionId }); results.RevisionId = revisionId; results.Created = saveTime; results.QuerySetId = querySetId; } else { results.RevisionId = context.Revision != null ? context.Revision.Id : context.QuerySet.CurrentRevisionId; results.QuerySetId = context.QuerySet.Id; results.Created = null; } if (context.Title != null) { results.Slug = context.Title.URLFriendly(); } QueryRunner.LogRevisionExecution(CurrentUser, siteId, results.RevisionId); // Consider handling this XSS condition (?) in the ToJson() method instead, if possible return Content(results.ToJson().Replace("/", "\\/"), "application/json"); }
public static AsyncResult Execute(ParsedQuery query, User user, Site site, QueryContextData context) { string userTag = user.IsAnonymous ? user.IPAddress : user.Id.ToString(); List <Task> activeTasks; running.TryGetValue(userTag, out activeTasks); if (activeTasks != null) { lock (activeTasks) { if (activeTasks.Where(t => !t.IsCompleted).Count() >= AppSettings.ConcurrentQueries) { throw new ApplicationException("Too many queries are running, you may only run " + AppSettings.ConcurrentQueries + " queries at a time"); } } } else { running.TryAdd(userTag, new List <Task>()); activeTasks = running[userTag]; } AsyncResult result = new AsyncResult { JobId = Guid.NewGuid(), State = AsyncState.Pending, ParsedQuery = query, Site = site, LastPoll = DateTime.UtcNow, QueryContextData = context }; Task task = new Task(() => { try { result.QueryResults = QueryRunner.GetResults(query, site, user, result); if (result.State == AsyncState.Pending) { result.State = AsyncState.Success; } } catch (Exception e) { result.Exception = e; result.State = AsyncState.Failure; } }); task.ContinueWith(ignore => { result.CompletionDate = DateTime.UtcNow; lock (activeTasks) { activeTasks.RemoveAll(t => t.IsCompleted); } }); result.Task = task; jobs.TryAdd(result.JobId, result); task.Start(); lock (activeTasks) { activeTasks.Add(task); } // give it some time to get results ... System.Threading.Thread.Sleep(50); return(result); }