public async Task <IHttpActionResult> PostNewCampaign([FromBody] Campaign_CreateBM model)
        {
            if (db.Campaigns.Where(c => c.Title == model.Title).Count() > 0)
            {
                return(Conflict());
            }

            var thisUserId = int.Parse(User.Identity.GetUserId());

            if (db.Campaigns.Where(c => c.CreatedById == thisUserId &&
                                   (c.Status == CampaignStatus.PreliminaryRegistered ||
                                    c.Status == CampaignStatus.CompletelyRegistered ||
                                    c.Status == CampaignStatus.Waiting)).Count() >= 2)
            {
                CustomHttpExceptions.CustomHttpException(HttpStatusCode.Conflict, "The user cannot create a campaign because they already have maximum two 'Not-Accepted' campaigns");
            }

            var todayUtc = DateTime.UtcNow.Date;

            if (
                db.Campaigns.Where(c => c.CreatedById == thisUserId && c.CreatedDateUtc >= todayUtc).Count()
                >= ApplicationDbContext.GlobalSettings.SecurityDoSMaxCampaignsPerUserPerDay
                )
            {
                CustomHttpExceptions.CustomHttpException(HttpStatusCode.Conflict, "The user must wait up to one day to create a new campaign");
            }

            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }
            //NOTE: We use Ganss sanitizer for HTML (perhaps only Story) and our own MySanitizer for the rest
            model.Title   = Helpers.MySanitizer.StrictSanitize(model.Title);
            model.Tagline = Helpers.MySanitizer.StrictSanitize(model.Tagline);

            var campaign = new Campaign
            {
                Status      = CampaignStatus.PreliminaryRegistered,
                CreatedById = thisUserId,
                TargetFund  = model.TargetFund,
                Title       = model.Title,
                Tagline     = model.Tagline
            };

            AddOrUpdateSlug(ref campaign);

            db.Campaigns.Add(campaign);
            await db.SaveChangesAsync();

            // return CreatedAtRoute("DefaultApi", new { id = campaign.Id }, campaign);
            return(Created <Campaign>("DefaultApi", campaign));
        }
        private void AddTags(string[] tags, Campaign campaign)
        {
            var lengthyTags = tags.Where(t => t.Length > 20);

            if (lengthyTags.Count() > 0)
            {
                CustomHttpExceptions.CustomBadRequest("Some tags are lengthy:" + string.Join(",", lengthyTags));
            }
            //Sanitize tags
            tags = tags.Select(t => Helpers.MySanitizer.StrictSanitize(t)).ToArray();

            /*NOTE:AddRange is a no-op if the entity is already in the context in the Added state, but the tags added
             * previously are in Unchanged state so we have to add only new entities*/
            var oldTags = campaign.TagMaps.ToList();
            var newTags = tags.Select(t => new CampaignTag {
                Name = t
            }).ToList();

            //Remove only old tags that are not in new tags
            foreach (var t in oldTags)
            {
                if (!tags.Contains(t.CampaignTagName))
                {
                    db.CampaignTagMaps.Remove(t);
                }
            }

            //add only new tags that are not in old tags
            var oldTagNames = oldTags.Select(ot => ot.CampaignTagName).ToArray();

            foreach (var nt in newTags)
            {
                if (!TagExist(nt))
                {
                    db.CampaignTags.Add(nt);
                }
                if (!oldTagNames.Contains(nt.Name))
                {
                    db.CampaignTagMaps.Add(new CampaignTagMap {
                        CampaignTagName = nt.Name, CampaignId = campaign.Id
                    });
                }
            }
        }
        public bool CheckandUpdateWaitingStatus(Campaign campaign, string status)
        {
            if (string.Equals(status,
                              CampaignStatus.Waiting.ToString(),
                              StringComparison.OrdinalIgnoreCase))
            {
                /*
                 * NOTE: This is not neccessary and in some cases against RESTful implementation
                 * although not practical from client-side point of view there are no problems with changing
                 * some campaign props and request a waiting status at the same request!
                 * //counts non-null values of model
                 * var nonNullCount = typeof(UpdateCampaignVM).GetProperties()
                 *  .Where(p => p.GetValue(model) != null)
                 *  .Count();
                 * if (nonNullCount > 1) {
                 *  CustomBadRequest(string.Format(
                 *      "Model can not have Status value and other values at the same time: {0} non-null values in model"
                 *      ,nonNullCount));
                 * }
                 */

                ModelState.Clear();

                var validationProps = typeof(Campaign_WaitingValidationModel).GetProperties().Select(p => p.Name).ToList();
                //Check Null or Empty values of campaign
                var nullOrWhiteSpaceProps =
                    typeof(Campaign).GetProperties()
                    .Where(p => validationProps.Contains(p.Name))
                    .Where(p => string.IsNullOrWhiteSpace((p.GetValue(campaign) ?? "").ToString()))
                    .Select(p => p.Name);

                if (nullOrWhiteSpaceProps.Count() > 0)
                {
                    CustomHttpExceptions.CustomBadRequest("The following properties of campaign have Null or Empty values:"
                                                          + string.Join(",", nullOrWhiteSpaceProps.ToArray()));
                }
                return(true);
            }
            return(false);
        }
        public async Task <IHttpActionResult> PostCampaign(string id_or_slug, Campaign_UpdateBM model, bool soft_delete = false)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            var campaign = GetCampaignByIdOrSlug(id_or_slug);


            //Only the one who created the campaign can edit it
            //TODO: What about admins?
            var userId = User.Identity.GetUserId();
            var user   = db.Users.Find(int.Parse(userId));

            if (campaign.CreatedById.ToString() != userId)
            {
                CustomHttpExceptions.CustomHttpException(HttpStatusCode.Unauthorized,
                                                         string.Format(
                                                             "Unauthorized: The user (Id = {0}) who has requested the update is not the creator of the campaign!",
                                                             userId)
                                                         );
            }

            /*TODO: think about these conditions and code business logic accordingly:
             * 1) The user decides to cancel campaign in 'Waiting' status
             * 2) The user decides to interrupt 'Waiting' status and do some changes
             * 3) The user decides to remove an 'Approved' or 'Waiting' campaign
             */
            if (campaign.Status.HasFlag(CampaignStatus.ReadOnly))
            {
                CustomHttpExceptions.CustomHttpException(HttpStatusCode.Forbidden, "Campaign can not be modified because of its current status");
            }

            if (soft_delete)
            {
                campaign.RemovedFlagUtc  = DateTime.UtcNow;
                db.Entry(campaign).State = EntityState.Modified;
                await db.SaveChangesAsync();

                return(StatusCode(HttpStatusCode.NoContent));
            }

            UpdateCampaignByUpdateCampaignVM(ref campaign, model);

            AddOrUpdateSlug(ref campaign);

            //Checks whether there is a base64 thumbnail
            if (model.Base64Thumbnail != null)
            {
                var uploaderResponse = await Helpers.UploadHelper.UploadBase64ImageAsync(db, userId, model.Base64Thumbnail, FileServerTokenType.CampaignImageUpload);

                if (uploaderResponse.StatusCode == HttpStatusCode.OK || uploaderResponse.StatusCode == HttpStatusCode.Created)
                {
                    model.ThumbnailPath            = uploaderResponse.FilePath;
                    model.ThumbnailServerId        = uploaderResponse.FileServerId;
                    campaign.ThumbnailFileServerId = model.ThumbnailServerId;
                    campaign.ThumbnailFilePath     = model.ThumbnailPath;
                    Console.WriteLine("Thumbnail Uploaded. Thumbnail Path:" + campaign.ThumbnailFilePath);
                }

                else
                {
                    Console.WriteLine("Thumbnail Upload Error Code:" + uploaderResponse.StatusCode);
                    Console.WriteLine(uploaderResponse.Message);
                }
            }


            if (model.CityId != null)
            {
                if (campaign.Location != null)
                {
                    var location = campaign.Location;
                    location.CityId          = (int)model.CityId;
                    db.Entry(location).State = EntityState.Modified;
                }
                else
                {
                    campaign.Location = new Location {
                        CityId = (int)model.CityId
                    };
                }
            }


            var waitingStatus = CheckandUpdateWaitingStatus(campaign, model.Status);

            if (waitingStatus)
            {
                campaign.Status = CampaignStatus.Waiting | CampaignStatus.ReadOnly;
                if (campaign.Account == null)
                {
                    campaign.Account = new Account {
                        AccountName = "cmp_" + campaign.Id.ToString(), AccountType = AccountType.CampaignAccount
                    };
                }
            }

            if (model.Tags != null)
            {
                AddTags(model.Tags, campaign);
            }

            db.Entry(campaign).State = EntityState.Modified;

            await db.SaveChangesAsync();

            return(StatusCode(HttpStatusCode.NoContent));
        }