Пример #1
0
        /// <summary>
        /// Gets the active threads visible to the user.
        /// </summary>
        /// <param name="accessableForums">A list of accessable forums IDs, which the user has permission to access.</param>
        /// <param name="hoursThreshold">The hours threshold for the query to fetch the active threads. All threads within this threshold's period of time (in hours)
        /// are fetched.</param>
        /// <param name="forumsWithThreadsFromOthers">The forums for which the calling user can view other users' threads. Can be null</param>
        /// <param name="userId">The userid of the calling user.</param>
        /// <returns>a list with objects representing the Active threads</returns>
        public static async Task <List <AggregatedThreadRow> > GetActiveThreadsAggregatedData(List <int> accessableForums, short hoursThreshold,
                                                                                              List <int> forumsWithThreadsFromOthers, int userId)
        {
            if (accessableForums == null || accessableForums.Count <= 0)
            {
                return(null);
            }

            var qf = new QueryFactory();
            var q  = qf.Create()
                     .Select <AggregatedThreadRow>(ThreadGuiHelper.BuildQueryProjectionForAllThreadsWithStatsWithForumName(qf).ToArray())
                     .From(ThreadGuiHelper.BuildFromClauseForAllThreadsWithStats(qf)
                           .InnerJoin(qf.Forum).On(ThreadFields.ForumID.Equal(ForumFields.ForumID)))
                     .Where(ThreadFields.ForumID.In(accessableForums)
                            .And(ThreadFields.IsClosed.Equal(false))
                            .And(ThreadFields.MarkedAsDone.Equal(false))
                            .And(MessageFields.PostingDate.Source("LastMessage").GreaterEqual(DateTime.Now.AddHours((double)0 - hoursThreshold)))
                            .And(ThreadGuiHelper.CreateThreadFilter(forumsWithThreadsFromOthers, userId)))
                     .OrderBy(MessageFields.PostingDate.Source("LastMessage").Ascending());

            using (var adapter = new DataAccessAdapter())
            {
                return(await adapter.FetchQueryAsync(q).ConfigureAwait(false));
            }
        }
Пример #2
0
        /// <summary>
        /// Gets the active threads.
        /// </summary>
        /// <param name="accessableForums">A list of accessable forums IDs, which the user has permission to access.</param>
        /// <param name="hoursThreshold">The hours threshold for the query to fetch the active threads. All threads within this threshold's period of time (in hours)
        /// are fetched.</param>
        /// <param name="forumsWithOnlyOwnThreads">The forums for which the calling user can view other users' threads. Can be null</param>
        /// <param name="userID">The userid of the calling user.</param>
        /// <returns>a dataView of Active threads</returns>
        public static DataView GetActiveThreadsAsDataView(List <int> accessableForums, short hoursThreshold, List <int> forumsWithThreadsFromOthers, int userID)
        {
            if (accessableForums == null || accessableForums.Count <= 0)
            {
                return(null);
            }

            var qf = new QueryFactory();
            var q  = qf.Create()
                     .Select(new List <object>(ThreadGuiHelper.BuildQueryProjectionForAllThreadsWithStats(qf))
            {
                ForumFields.ForumName
            }
                             .ToArray())
                     .From(ThreadGuiHelper.BuildFromClauseForAllThreadsWithStats(qf)
                           .InnerJoin(qf.Forum).On(ThreadFields.ForumID == ForumFields.ForumID))
                     .Where((ThreadFields.ForumID == accessableForums)
                            .And(ThreadFields.IsClosed == false)
                            .And(ThreadFields.MarkedAsDone == false)
                            .And(ThreadFields.ThreadLastPostingDate >= DateTime.Now.AddHours((double)0 - hoursThreshold))
                            .And(ThreadGuiHelper.CreateThreadFilter(forumsWithThreadsFromOthers, userID)))
                     .OrderBy(ThreadFields.ThreadLastPostingDate.Ascending());
            var dao           = new TypedListDAO();
            var activeThreads = dao.FetchAsDataTable(q);

            return(activeThreads.DefaultView);
        }
Пример #3
0
        /// <summary>
        /// Gets the threads and accompanying statistics info, in the supportqueue specified. Only the threads which are in the forums in the list of
        /// accessable forums are returned.
        /// </summary>
        /// <param name="accessableForums">A list of accessable forums IDs, which the user has permission to access.</param>
        /// <param name="supportQueueID">The ID of the support queue to retrieve the threads for.</param>
        /// <returns>a dataView of Active threads</returns>
        public static DataView GetAllThreadsInSupportQueueAsDataView(List <int> accessableForums, int supportQueueID)
        {
            // return null, if the user does not have a valid list of forums to access
            if (accessableForums == null || accessableForums.Count <= 0)
            {
                return(null);
            }
            var qf = new QueryFactory();
            var q  = qf.Create();
            var projectionFields = new List <object>(ThreadGuiHelper.BuildQueryProjectionForAllThreadsWithStats(qf));

            projectionFields.AddRange(new[] {
                ForumFields.ForumName,
                UserFields.NickName.Source("PlacedInQueueUser").As("NickNamePlacedInQueue"),
                SupportQueueThreadFields.PlacedInQueueByUserID,
                SupportQueueThreadFields.PlacedInQueueOn,
                UserFields.NickName.Source("ClaimedThreadUser").As("NickNameClaimedThread"),
                SupportQueueThreadFields.ClaimedByUserID,
                SupportQueueThreadFields.ClaimedOn
            });
            q.Select(projectionFields.ToArray());
            q.From(ThreadGuiHelper.BuildFromClauseForAllThreadsWithStats(qf)
                   .InnerJoin(qf.Forum).On(ThreadFields.ForumID == ForumFields.ForumID)
                   .InnerJoin(qf.SupportQueueThread).On(ThreadFields.ThreadID == SupportQueueThreadFields.ThreadID)
                   .InnerJoin(qf.User.As("PlacedInQueueUser"))
                   .On(SupportQueueThreadFields.PlacedInQueueByUserID == UserFields.UserID.Source("PlacedInQueueUser"))
                   .LeftJoin(qf.User.As("ClaimedThreadUser"))
                   .On(SupportQueueThreadFields.ClaimedByUserID == UserFields.UserID.Source("ClaimedThreadUser")));
            q.Where((ThreadFields.ForumID == accessableForums).And(SupportQueueThreadFields.QueueID == supportQueueID));
            q.OrderBy(ThreadFields.ThreadLastPostingDate.Ascending());
            TypedListDAO dao            = new TypedListDAO();
            var          threadsInQueue = dao.FetchAsDataTable(q);

            return(threadsInQueue.DefaultView);
        }
Пример #4
0
        /// <summary>
        /// Creates the attachment filter. The filter filters on attachments with the specified approvalstate in the threads viewable by the calling user.
        /// </summary>
        /// <param name="accessableForums">The accessable forums.</param>
        /// <param name="forumsWithApprovalRight">The forums with approval right.</param>
        /// <param name="forumsWithThreadsFromOthers">The forums with threads from others.</param>
        /// <param name="userID">The user ID.</param>
        /// <param name="filter">The filter.</param>
        /// <returns>ready to use predicate expression for fetch actions on attachments with the approval state specified in the threads
        /// matching the forumID's.</returns>
        private static PredicateExpression CreateAttachmentFilter(List <int> accessableForums, List <int> forumsWithApprovalRight,
                                                                  List <int> forumsWithThreadsFromOthers, int userID, bool approvalState)
        {
            PredicateExpression filter = new PredicateExpression();

            // specify the filter for the accessable forums. Do this by a fieldcomparerange predicate and filter on Thread.ForumID. As 'accessableForums' is a list
            // the following statement will create a fieldcomparerange predicate for us.
            if (accessableForums.Count == 1)
            {
                // optimization, specify the only value instead of the range, so we won't get a WHERE Field IN (@param) query which is slow on some
                // databases, but we'll get a WHERE Field == @param
                filter.Add(ThreadFields.ForumID == accessableForums[0]);
            }
            else
            {
                filter.Add(ThreadFields.ForumID == accessableForums);
            }
            // specify the filter for the forums with approval rights:
            if (forumsWithApprovalRight.Count == 1)
            {
                // optimization, specify the only value instead of the range, so we won't get a WHERE Field IN (@param) query which is slow on some
                // databases, but we'll get a WHERE Field == @param
                filter.Add(ThreadFields.ForumID == forumsWithApprovalRight[0]);
            }
            else
            {
                filter.Add(ThreadFields.ForumID == forumsWithApprovalRight);
            }
            // Also filter on the threads viewable by the passed in userid, which is the caller of the method. If a forum isn't in the list of
            // forumsWithThreadsFromOthers, only the sticky threads and the threads started by userid should be counted / taken into account.
            filter.AddWithAnd(ThreadGuiHelper.CreateThreadFilter(forumsWithApprovalRight, userID));
            // as last filter, we'll add a filter to only get the data for attachments which aren't approved yet.
            filter.AddWithAnd(AttachmentFields.Approved == false);
            return(filter);
        }
Пример #5
0
        /// <summary>
        /// Subscribes the user specified to the thread specified for notifications. A transaction can be specified to save the information inside the
        /// transaction specified. If the user is already subscribed to this thread, nothing is done
        /// </summary>
        /// <param name="threadId">The thread ID.</param>
        /// <param name="userId">The user ID.</param>
        /// <param name="adapter">The live adapter with an active transaction. Can be null, in which case a local adapter is used.</param>
        /// <returns></returns>
        public static async Task <bool> AddThreadToSubscriptionsAsync(int threadId, int userId, IDataAccessAdapter adapter)
        {
            var localAdapter = adapter == null;
            var adapterToUse = adapter ?? new DataAccessAdapter();

            try
            {
                // check if this user is already subscribed to this thread. If not, add a new subscription.
                if (await ThreadGuiHelper.GetThreadSubscriptionAsync(threadId, userId, adapterToUse) == null)
                {
                    // user isn't yet subscribed, add the subscription
                    return(await adapterToUse.SaveEntityAsync(new ThreadSubscriptionEntity { UserID = userId, ThreadID = threadId }).ConfigureAwait(false));
                }

                // already subscribed, no-op.
                return(true);
            }
            finally
            {
                if (localAdapter)
                {
                    adapterToUse.Dispose();
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Gets the active threads with statistics.
        /// </summary>
        /// <param name="accessableForums">A list of accessable forums IDs, which the user has permission to access.</param>
        /// <param name="hoursThreshold">The hours threshold for the query to fetch the active threads. All threads within this threshold's period of time (in hours)
        /// are fetched.</param>
        /// <param name="forumsWithOnlyOwnThreads">The forums for which the calling user can view other users' threads. Can be null</param>
        /// <param name="userID">The userid of the calling user.</param>
        /// <returns>
        /// a dataTable of Active threads with statistics
        /// </returns>
        public static DataTable GetActiveThreadsStatisticsAsDataTable(List <int> accessableForums, short hoursThreshold,
                                                                      List <int> forumsWithThreadsFromOthers, int userID)
        {
            // return null, if the user does not have a valid list of forums to access
            if (accessableForums == null || accessableForums.Count <= 0)
            {
                return(null);
            }

            var qf = new QueryFactory();
            var q  = qf.Create()
                     .Select(ThreadFields.ThreadID.CountDistinct().As("AmountThreads"),
                             MessageFields.MessageID.Count().As("AmountPostings"),
                             ThreadFields.ThreadLastPostingDate.Max().As("LastPostingDate"))
                     .From(qf.Thread.InnerJoin(qf.Message).On(ThreadFields.ThreadID == MessageFields.ThreadID))
                     .Where((ThreadFields.ForumID == accessableForums)
                            .And(ThreadFields.IsClosed == false)
                            .And(ThreadFields.MarkedAsDone == false)
                            .And(ThreadFields.ThreadLastPostingDate >= DateTime.Now.AddHours((double)0 - hoursThreshold))
                            .And(ThreadGuiHelper.CreateThreadFilter(forumsWithThreadsFromOthers, userID)));
            var dao = new TypedListDAO();

            return(dao.FetchAsDataTable(q));


            //// create dyn. list and pull statistics using that list.
            //ResultsetFields fields = new ResultsetFields(3);
            //fields.DefineField(ThreadFields.ThreadID, 0, "AmountThreads", string.Empty, AggregateFunction.CountDistinct);
            //fields.DefineField(MessageFields.MessageID, 1, "AmountPostings", string.Empty, AggregateFunction.Count);
            //fields.DefineField(ThreadFields.ThreadLastPostingDate, 2, "LastPostingDate", string.Empty, AggregateFunction.Max);

            //RelationCollection relations = new RelationCollection();
            //relations.Add(ThreadEntity.Relations.MessageEntityUsingThreadID);

            //PredicateExpression filter = new PredicateExpression();
            //// only the forums the user has access to
            //filter.Add(ThreadFields.ForumID == accessableForums.ToArray());
            //// only the threads which are not closed
            //filter.AddWithAnd(ThreadFields.IsClosed == false);
            //// only the threads which are active (== not done)
            //filter.AddWithAnd(ThreadFields.MarkedAsDone == false);
            //// only threads which have been updated in the last Globals.HoursForActiveThreadsTreshold hours
            //filter.AddWithAnd(ThreadFields.ThreadLastPostingDate >= DateTime.Now.AddHours((double)0 - hoursThreshold));

            //// Also filter on the threads viewable by the passed in userid, which is the caller of the method. If a forum isn't in the list of
            //// forumsWithThreadsFromOthers, only the sticky threads and the threads started by userid should be counted / taken into account.
            //IPredicateExpression threadFilter = ThreadGuiHelper.CreateThreadFilter(forumsWithThreadsFromOthers, userID);
            //filter.AddWithAnd(threadFilter);

            //TypedListDAO dao = new TypedListDAO();
            //DataTable toReturn = new DataTable();
            //dao.GetMultiAsDataTable(fields, toReturn, 0, null, filter, relations, true, null, null, 0, 0);
            //return toReturn;
        }
Пример #7
0
        /// <summary>
        /// Marks the thread as done.
        /// </summary>
        /// <param name="threadID">Thread ID.</param>
        /// <returns></returns>
        public static bool MarkThreadAsDone(int threadID)
        {
            // load the entity from the database
            ThreadEntity thread = ThreadGuiHelper.GetThread(threadID);

            if (thread == null)
            {
                // not found
                return(false);
            }

            // get the support queue the thread is in (if any)
            SupportQueueEntity containingSupportQueue = SupportQueueGuiHelper.GetQueueOfThread(threadID);

            thread.MarkedAsDone = true;

            // if the thread is in a support queue, the thread has to be removed from that queue. This is a multi-entity action and therefore we've to start a
            // transaction if that's the case. If not, we can use the easy route and simply save the thread and be done with it.
            if (containingSupportQueue == null)
            {
                // not in a queue, simply save the thread.
                return(thread.Save());
            }

            // in a queue, so remove from the queue and save the entity.
            Transaction trans = new Transaction(IsolationLevel.ReadCommitted, "MarkThreadDone");

            trans.Add(thread);
            try
            {
                // save the thread
                bool result = thread.Save();
                if (result)
                {
                    // save succeeded, so remove from queue, pass the current transaction to the method so the action takes place inside this transaction.
                    SupportQueueManager.RemoveThreadFromQueue(threadID, trans);
                }

                trans.Commit();
                return(true);
            }
            catch
            {
                // rollback transaction
                trans.Rollback();
                throw;
            }
            finally
            {
                trans.Dispose();
            }
        }
Пример #8
0
        /// <summary>
        /// Unsubscribes the specified user from the specified thread.
        /// </summary>
        /// <param name="threadID">The thread ID.</param>
        /// <param name="userID">The user ID.</param>
        /// <returns>true if delete succeeded, false otherwise</returns>
        public static bool RemoveSingleSubscription(int threadID, int userID)
        {
            ThreadSubscriptionEntity subscription = ThreadGuiHelper.GetThreadSubscription(threadID, userID);

            if (subscription != null)
            {
                // there's a subscription, delete it
                return(subscription.Delete());
            }
            else
            {
                return(true);
            }
        }
Пример #9
0
        /// <summary>
        /// Unsubscribes the specified user from the specified thread.
        /// </summary>
        /// <param name="threadId">The thread ID.</param>
        /// <param name="userId">The user ID.</param>
        /// <returns>true if delete succeeded, false otherwise</returns>
        public static async Task <bool> RemoveSingleSubscriptionAsync(int threadId, int userId)
        {
            var subscription = await ThreadGuiHelper.GetThreadSubscriptionAsync(threadId, userId);

            if (subscription != null)
            {
                // there's a subscription, delete it
                using (var adapter = new DataAccessAdapter())
                {
                    return(await adapter.DeleteEntityAsync(subscription).ConfigureAwait(false));
                }
            }

            return(true);
        }
Пример #10
0
        /// <summary>
        /// Marks the thread as done.
        /// </summary>
        /// <param name="threadId">Thread ID.</param>
        /// <returns></returns>
        public static async Task <bool> MarkThreadAsDoneAsync(int threadId)
        {
            var thread = await ThreadGuiHelper.GetThreadAsync(threadId);

            if (thread == null)
            {
                // not found
                return(false);
            }

            var containingSupportQueue = await SupportQueueGuiHelper.GetQueueOfThreadAsync(threadId);

            thread.MarkedAsDone = true;
            using (var adapter = new DataAccessAdapter())
            {
                // if the thread is in a support queue, the thread has to be removed from that queue. This is a multi-entity action and therefore we've to start a
                // transaction if that's the case. If not, we can use the easy route and simply save the thread and be done with it.
                if (containingSupportQueue == null)
                {
                    // not in a queue, simply save the thread.
                    return(await adapter.SaveEntityAsync(thread).ConfigureAwait(false));
                }

                // in a queue, so remove from the queue and save the entity.
                await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "MarkThreadDone").ConfigureAwait(false);

                try
                {
                    // save the thread
                    var result = await adapter.SaveEntityAsync(thread).ConfigureAwait(false);

                    if (result)
                    {
                        // save succeeded, so remove from queue, pass the current adapter to the method so the action takes place inside this transaction.
                        await SupportQueueManager.RemoveThreadFromQueueAsync(threadId, adapter);
                    }

                    adapter.Commit();
                    return(true);
                }
                catch
                {
                    // rollback transaction
                    adapter.Rollback();
                    throw;
                }
            }
        }
Пример #11
0
        /// <summary>
        /// Updates the memo field for the given thread
        /// </summary>
        /// <param name="threadID">Thread ID.</param>
        /// <param name="memo">Memo.</param>
        /// <returns></returns>
        public static bool UpdateMemo(int threadID, string memo)
        {
            // load the entity from the database
            ThreadEntity thread = ThreadGuiHelper.GetThread(threadID);

            if (thread == null)
            {
                // not found
                return(false);
            }

            thread.Memo = memo;

            //update the entity in the database
            return(thread.Save());
        }
Пример #12
0
        /// <summary>
        /// Moves the given thread to the given forum.
        /// </summary>
        /// <param name="threadId">ID of thread to move</param>
        /// <param name="newForumId">ID of forum to move the thread to</param>
        /// <returns></returns>
        public static async Task <bool> MoveThreadAsync(int threadId, int newForumId)
        {
            var thread = await ThreadGuiHelper.GetThreadAsync(threadId);

            if (thread == null)
            {
                // not found
                return(false);
            }

            thread.ForumID = newForumId;
            using (var adapter = new DataAccessAdapter())
            {
                return(await adapter.SaveEntityAsync(thread).ConfigureAwait(false));
            }
        }
Пример #13
0
        /// <summary>
        /// Moves the given thread to the given forum.
        /// </summary>
        /// <param name="threadID">ID of thread to move</param>
        /// <param name="newForumID">ID of forum to move the thread to</param>
        /// <returns></returns>
        public static bool MoveThread(int threadID, int newForumID)
        {
            // load the entity from the database
            ThreadEntity thread = ThreadGuiHelper.GetThread(threadID);

            if (thread == null)
            {
                // not found
                return(false);
            }

            // update the ForumID field with the new value
            thread.ForumID = newForumID;

            // save the updated entity back to the database
            return(thread.Save());
        }
Пример #14
0
        /// <summary>
        /// Gets the bookmarks with statistics for the user specified.
        /// </summary>
        /// <param name="userID">User ID.</param>
        /// <returns></returns>
        public static async Task <List <AggregatedThreadRow> > GetBookmarksAggregatedDataAsync(int userID)
        {
            var qf = new QueryFactory();
            var q  = qf.Create()
                     .Select <AggregatedThreadRow>(ThreadGuiHelper.BuildQueryProjectionForAllThreadsWithStatsWithForumName(qf).ToArray())
                     .From(ThreadGuiHelper.BuildFromClauseForAllThreadsWithStats(qf)
                           .InnerJoin(qf.Forum).On(ThreadFields.ForumID.Equal(ForumFields.ForumID)))
                     .Where(ThreadFields.ThreadID.In(qf.Create()
                                                     .Select(BookmarkFields.ThreadID)
                                                     .Where(BookmarkFields.UserID.Equal(userID))))
                     .OrderBy(MessageFields.PostingDate.Source("LastMessage").Descending());

            using (var adapter = new DataAccessAdapter())
            {
                return(await adapter.FetchQueryAsync(q).ConfigureAwait(false));
            }
        }
Пример #15
0
        /// <summary>
        /// Gets the last pageSize threads in which the user specified participated with one or more messages for the page specified.
        /// Threads which aren't visible for the calling user are filtered out. If pageNumber is 0, pageSize is used to limit the list to the pageSize
        /// </summary>
        /// <param name="accessableForums">A list of accessable forums IDs, which the user calling the method has permission to access.</param>
        /// <param name="participantUserId">The participant user ID of the user of which the threads have to be obtained.</param>
        /// <param name="forumsWithThreadsFromOthers">The forums with threads from others.</param>
        /// <param name="callingUserId">The calling user ID.</param>
        /// <param name="pageSize">Size of the page.</param>
        /// <param name="pageNumber">The page number to fetch.</param>
        /// <returns>a list with objects representing the last threads for the user</returns>
        public static async Task <List <AggregatedThreadRow> > GetLastThreadsForUserAggregatedDataAsync(List <int> accessableForums, int participantUserId,
                                                                                                        List <int> forumsWithThreadsFromOthers, int callingUserId,
                                                                                                        int pageSize, int pageNumber)
        {
            // return null, if the user does not have a valid list of forums to access
            if (accessableForums == null || accessableForums.Count <= 0)
            {
                return(null);
            }

            var numberOfThreadsToFetch = pageSize;

            if (numberOfThreadsToFetch <= 0)
            {
                numberOfThreadsToFetch = 25;
            }

            var qf = new QueryFactory();
            var q  = qf.Create()
                     .Select <AggregatedThreadRow>(ThreadGuiHelper.BuildQueryProjectionForAllThreadsWithStatsWithForumName(qf).ToArray())
                     .From(ThreadGuiHelper.BuildFromClauseForAllThreadsWithStats(qf)
                           .InnerJoin(qf.Forum).On(ThreadFields.ForumID.Equal(ForumFields.ForumID)))
                     .Where(ThreadFields.ForumID.In(accessableForums)
                            .And(ThreadFields.ThreadID.In(qf.Create()
                                                          .Select(MessageFields.ThreadID)
                                                          .Where(MessageFields.PostedByUserID.Equal(participantUserId))))
                            .And(ThreadGuiHelper.CreateThreadFilter(forumsWithThreadsFromOthers, callingUserId)))
                     .OrderBy(MessageFields.PostingDate.Source("LastMessage").Descending());

            if (pageNumber <= 0)
            {
                // no paging
                // get the last numberOfThreadsToFetch, so specify a limit equal to the numberOfThreadsToFetch specified
                q.Limit(numberOfThreadsToFetch);
            }
            else
            {
                // use paging
                q.Page(pageNumber, numberOfThreadsToFetch);
            }

            using (var adapter = new DataAccessAdapter())
            {
                return(await adapter.FetchQueryAsync(q).ConfigureAwait(false));
            }
        }
Пример #16
0
        /// <summary>
        /// Updates the memo field for the given thread
        /// </summary>
        /// <param name="threadId">Thread ID.</param>
        /// <param name="memo">Memo.</param>
        /// <returns></returns>
        public static async Task <bool> UpdateMemoAsync(int threadId, string memo)
        {
            // load the entity from the database
            var thread = await ThreadGuiHelper.GetThreadAsync(threadId);

            if (thread == null)
            {
                // not found
                return(false);
            }

            using (var adapter = new DataAccessAdapter())
            {
                thread.Memo = memo;
                return(await adapter.SaveEntityAsync(thread).ConfigureAwait(false));
            }
        }
Пример #17
0
        /// <summary>
        /// Gets the bookmarks with statistics for the user specified.
        /// </summary>
        /// <param name="userID">User ID.</param>
        /// <returns></returns>
        public static DataView GetBookmarksAsDataView(int userID)
        {
            var qf = new QueryFactory();
            var q  = qf.Create()
                     .Select(new List <object>(ThreadGuiHelper.BuildQueryProjectionForAllThreadsWithStats(qf))
            {
                ForumFields.ForumName,
                ForumFields.SectionID
            }.ToArray())
                     .From(ThreadGuiHelper.BuildFromClauseForAllThreadsWithStats(qf)
                           .InnerJoin(qf.Forum).On(ThreadFields.ForumID == ForumFields.ForumID))
                     .Where(ThreadFields.ThreadID.In(qf.Create().Select(BookmarkFields.ThreadID).Where(BookmarkFields.UserID == userID)))
                     .OrderBy(ThreadFields.ThreadLastPostingDate.Descending());
            var dao = new TypedListDAO();
            var bookmarkedThreads = dao.FetchAsDataTable(q);

            return(bookmarkedThreads.DefaultView);
        }
Пример #18
0
        /// <summary>
        /// Modifies the given properties of the given thread.
        /// </summary>
        /// <param name="threadID">The threadID of the thread which properties should be changed</param>
        /// <param name="subject">The new subject for this thread</param>
        /// <param name="isSticky">The new value for IsSticky</param>
        /// <param name="isClosed">The new value for IsClosed</param>
        /// <returns></returns>
        public static bool ModifyThreadProperties(int threadID, string subject, bool isSticky, bool isClosed)
        {
            // load the entity from the database
            ThreadEntity thread = ThreadGuiHelper.GetThread(threadID);

            if (thread == null)
            {
                // not found
                return(false);
            }

            // update the fields with new values
            thread.Subject  = subject;
            thread.IsSticky = isSticky;
            thread.IsClosed = isClosed;

            // save the updated entity back to the database
            return(thread.Save());
        }
Пример #19
0
        /// <summary>
        /// Gets the last pageSize threads in which the user specified participated with one or more messages for the page specified.
        /// Threads which aren't visible for the calling user are filtered out. If pageNumber is 0, pageSize is used to limit the list to the pageSize
        /// </summary>
        /// <param name="accessableForums">A list of accessable forums IDs, which the user calling the method has permission to access.</param>
        /// <param name="participantUserID">The participant user ID of the user of which the threads have to be obtained.</param>
        /// <param name="forumsWithThreadsFromOthers">The forums with threads from others.</param>
        /// <param name="callingUserID">The calling user ID.</param>
        /// <param name="pageSize">Size of the page.</param>
        /// <param name="pageNumber">The page number to fetch.</param>
        /// <returns>a dataView of the threads requested</returns>
        public static DataView GetLastThreadsForUserAsDataView(List <int> accessableForums, int participantUserID,
                                                               List <int> forumsWithThreadsFromOthers, int callingUserID, int pageSize, int pageNumber)
        {
            // return null, if the user does not have a valid list of forums to access
            if (accessableForums == null || accessableForums.Count <= 0)
            {
                return(null);
            }

            int numberOfThreadsToFetch = pageSize;

            if (numberOfThreadsToFetch <= 0)
            {
                numberOfThreadsToFetch = 25;
            }

            var qf = new QueryFactory();
            var q  = qf.Create()
                     .Select(ThreadGuiHelper.BuildQueryProjectionForAllThreadsWithStats(qf))
                     .From(ThreadGuiHelper.BuildFromClauseForAllThreadsWithStats(qf))
                     .Where((ThreadFields.ForumID == accessableForums)
                            .And(ThreadFields.ThreadID.In(qf.Create()
                                                          .Select(MessageFields.ThreadID)
                                                          .Where(MessageFields.PostedByUserID == participantUserID)))
                            .And(ThreadGuiHelper.CreateThreadFilter(forumsWithThreadsFromOthers, callingUserID)))
                     .OrderBy(ThreadFields.ThreadLastPostingDate.Descending());

            if (pageNumber <= 0)
            {
                // no paging
                // get the last numberOfThreadsToFetch, so specify a limit equal to the numberOfThreadsToFetch specified
                q.Limit(numberOfThreadsToFetch);
            }
            else
            {
                // use paging
                q.Page(pageNumber, numberOfThreadsToFetch);
            }
            var dao         = new TypedListDAO();
            var lastThreads = dao.FetchAsDataTable(q);

            return(lastThreads.DefaultView);
        }
Пример #20
0
        /// <summary>
        /// Marks the thread as un-done, and add it to the default queue of the forum.
        /// </summary>
        /// <param name="threadID">Thread ID</param>
        /// <returns></returns>
        public static bool UnMarkThreadAsDone(int threadID, int userID)
        {
            // load the entity from the database
            ThreadEntity thread = ThreadGuiHelper.GetThread(threadID);

            if (thread == null)
            {
                // not found
                return(false);
            }

            thread.MarkedAsDone = false;

            ForumEntity forum = new ForumEntity(thread.ForumID);

            // Save the thread and add it to the default queue of the forum.
            Transaction trans = new Transaction(IsolationLevel.ReadCommitted, "MarkThreadUnDone");

            trans.Add(thread);
            try
            {
                thread.Save();

                if ((forum.Fields.State == EntityState.Fetched) && (forum.DefaultSupportQueueID.HasValue))
                {
                    // not in a queue, and the forum has a default queue. Add the thread to the queue of the forum
                    SupportQueueManager.AddThreadToQueue(threadID, forum.DefaultSupportQueueID.Value, userID, trans);
                }

                trans.Commit();
                return(true);
            }
            catch
            {
                // rollback transaction
                trans.Rollback();
                throw;
            }
            finally
            {
                trans.Dispose();
            }
        }
Пример #21
0
        /// <summary>
        /// Subscribes the user specified to the thread specified for notifications. A transaction can be specified to save the information inside the
        /// transaction specified. If the user is already subscribed to this thread, nothing is done
        /// </summary>
        /// <param name="threadID">The thread ID.</param>
        /// <param name="userID">The user ID.</param>
        /// <param name="transactionToUse">The transaction to use. If no transaction is specified, no transaction is created</param>
        /// <returns></returns>
        public static bool AddThreadToSubscriptions(int threadID, int userID, Transaction transactionToUse)
        {
            // check if this user is already subscribed to this thread. If not, add a new subscription.
            ThreadSubscriptionEntity subscription = ThreadGuiHelper.GetThreadSubscription(threadID, userID, transactionToUse);

            if (subscription == null)
            {
                // user isn't yet subscribed, add the subscription
                subscription          = new ThreadSubscriptionEntity();
                subscription.UserID   = userID;
                subscription.ThreadID = threadID;
                if (transactionToUse != null)
                {
                    transactionToUse.Add(subscription);
                }
                return(subscription.Save());
            }
            // already subscribed, no-op.
            return(true);
        }
Пример #22
0
        /// <summary>
        /// Gets the row count for the set of threads in which the user specified participated with one or more messages for the page specified.
        /// Threads which aren't visible for the calling user are filtered out.
        /// </summary>
        /// <param name="accessableForums">A list of accessable forums IDs, which the user calling the method has permission to access.</param>
        /// <param name="participantUserID">The participant user ID of the user of which the threads have to be obtained.</param>
        /// <param name="forumsWithThreadsFromOthers">The forums with threads from others.</param>
        /// <param name="callingUserID">The calling user ID.</param>
        /// <returns>a dataView of the threads requested</returns>
        public static int GetRowCountLastThreadsForUserAsDataView(List <int> accessableForums, int participantUserID,
                                                                  List <int> forumsWithThreadsFromOthers, int callingUserID)
        {
            // return null, if the user does not have a valid list of forums to access
            if (accessableForums == null || accessableForums.Count <= 0)
            {
                return(0);
            }
            var qf = new QueryFactory();
            var q  = qf.Create()
                     .Select(ThreadGuiHelper.BuildQueryProjectionForAllThreadsWithStats(qf))
                     .From(ThreadGuiHelper.BuildFromClauseForAllThreadsWithStats(qf))
                     .Where((ThreadFields.ForumID == accessableForums)
                            .And(ThreadFields.ThreadID.In(qf.Create()
                                                          .Select(MessageFields.ThreadID)
                                                          .Where(MessageFields.PostedByUserID == participantUserID)))
                            .And(ThreadGuiHelper.CreateThreadFilter(forumsWithThreadsFromOthers, callingUserID)));
            var dao = new TypedListDAO();

            return(dao.GetScalar <int>(qf.Create().Select(Functions.CountRow()).From(q), null));
        }
Пример #23
0
        /// <summary>
        /// Marks the thread as un-done, and add it to the default queue of the forum.
        /// </summary>
        /// <param name="threadId">Thread ID</param>
        /// <param name="userId">the user adding the thread to a queue by unmarking it as done </param>
        /// <returns></returns>
        public static async Task <bool> UnMarkThreadAsDoneAsync(int threadId, int userId)
        {
            var thread = await ThreadGuiHelper.GetThreadAsync(threadId);

            if (thread == null)
            {
                // not found
                return(false);
            }

            thread.MarkedAsDone = false;
            using (var adapter = new DataAccessAdapter())
            {
                // Save the thread and add it to the default queue of the forum.
                await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "MarkThreadUnDone").ConfigureAwait(false);

                try
                {
                    await adapter.SaveEntityAsync(thread, true).ConfigureAwait(false);

                    var q     = new QueryFactory().Forum.Where(ForumFields.ForumID.Equal(thread.ForumID));
                    var forum = await adapter.FetchFirstAsync(q).ConfigureAwait(false);

                    if (forum?.DefaultSupportQueueID != null)
                    {
                        // not in a queue, and the forum has a default queue. Add the thread to the queue of the forum
                        await SupportQueueManager.AddThreadToQueueAsync(threadId, forum.DefaultSupportQueueID.Value, userId, adapter);
                    }

                    adapter.Commit();
                    return(true);
                }
                catch
                {
                    // rollback transaction
                    adapter.Rollback();
                    throw;
                }
            }
        }
Пример #24
0
        /// <summary>
        /// Gets the threads and accompanying statistics info, in the supportqueues specified. Only the threads which are in the forums in the list of
        /// accessable forums are returned.
        /// </summary>
        /// <param name="accessableForums">A list of accessable forums IDs, which the user has permission to access.</param>
        /// <param name="supportQueueIds">The support queue IDs to obtain the threads info for.</param>
        /// <returns>
        /// a list of aggregated support queue contents rows, one per thread, or an empty list if no forums were accessible.
        /// </returns>
        public static async Task <List <AggregatedSupportQueueContentsRow> > GetAllThreadsInSpecifiedSupportQueuesAsync(List <int> accessableForums, int[] supportQueueIds)
        {
            // return null, if the user does not have a valid list of forums to access
            if (accessableForums == null || accessableForums.Count <= 0)
            {
                return(new List <AggregatedSupportQueueContentsRow>());
            }

            var qf = new QueryFactory();
            var projectionFields = new List <object>(ThreadGuiHelper.BuildQueryProjectionForAllThreadsWithStatsWithForumName(qf));

            projectionFields.AddRange(new[]
            {
                SupportQueueThreadFields.QueueID,
                UserFields.NickName.Source("PlacedInQueueUser").As("PlacedInQueueByNickName"),
                SupportQueueThreadFields.PlacedInQueueByUserID,
                SupportQueueThreadFields.PlacedInQueueOn,
                UserFields.NickName.Source("ClaimedThreadUser").As("ClaimedByNickName"),
                SupportQueueThreadFields.ClaimedByUserID,
                SupportQueueThreadFields.ClaimedOn
            });
            var q = qf.Create()
                    .Select <AggregatedSupportQueueContentsRow>(projectionFields.ToArray())
                    .From(ThreadGuiHelper.BuildFromClauseForAllThreadsWithStats(qf)
                          .InnerJoin(qf.Forum).On(ThreadFields.ForumID.Equal(ForumFields.ForumID))
                          .InnerJoin(qf.SupportQueueThread).On(ThreadFields.ThreadID.Equal(SupportQueueThreadFields.ThreadID))
                          .InnerJoin(qf.User.As("PlacedInQueueUser"))
                          .On(SupportQueueThreadFields.PlacedInQueueByUserID.Equal(UserFields.UserID.Source("PlacedInQueueUser")))
                          .LeftJoin(qf.User.As("ClaimedThreadUser"))
                          .On(SupportQueueThreadFields.ClaimedByUserID.Equal(UserFields.UserID.Source("ClaimedThreadUser"))))
                    .Where(ThreadFields.ForumID.In(accessableForums.ToArray()).And(SupportQueueThreadFields.QueueID.In(supportQueueIds)))
                    .OrderBy(SupportQueueThreadFields.QueueID.Ascending(), MessageFields.PostingDate.Source("LastMessage").Ascending());

            using (var adapter = new DataAccessAdapter())
            {
                return(await adapter.FetchQueryAsync(q).ConfigureAwait(false));
            }
        }
Пример #25
0
        /// <summary>
        /// Returns a list with aggregated data objects, one per thread, for the requested forum and page
        /// </summary>
        /// <param name="forumId">ID of Forum for which the Threadlist is required</param>
        /// <param name="pageNumber">The page number to fetch, which is used to fetch non-sticky posts</param>
        /// <param name="pageSize">The number of rows to fetch for the page. </param>
        /// <param name="canViewNormalThreadsStartedByOthers">If set to true, the user calling the method has the right to view threads started by others.
        /// Otherwise only the threads started by the user calling the method are returned.</param>
        /// <param name="userId">The userid of the user calling the method.</param>
        /// <returns>List with all the thread info, aggregated. Sticky threads are sorted to the top.</returns>
        public static async Task <List <AggregatedThreadRow> > GetAllThreadsInForumAggregatedDataAsync(int forumId, int pageNumber, int pageSize,
                                                                                                       bool canViewNormalThreadsStartedByOthers, int userId)
        {
            // create a query which always fetches the sticky threads, and besides those the threads which are visible to the user.
            // then sort the sticky threads at the top and page through the resultset.
            var qf          = new QueryFactory();
            var offsetStart = pageSize * (pageNumber - 1);

            if (offsetStart < 0)
            {
                offsetStart = 0;
            }
            var q = qf.Create()
                    .From(ThreadGuiHelper.BuildFromClauseForAllThreadsWithStats(qf))
                    .Where(ThreadFields.ForumID.Equal(forumId))
                    .OrderBy(ThreadFields.IsSticky.Descending(), MessageFields.PostingDate.Source("LastMessage").Descending())
                    .Select <AggregatedThreadRow>(ThreadGuiHelper.BuildQueryProjectionForAllThreadsWithStats(qf).ToArray())
                    .Offset(offsetStart)                       // skip the pages we don't need.
                    .Limit(pageSize + 1);                      // fetch 1 row extra, which we can use to determine whether there are more pages left.

            // if the user can't view threads started by others, filter out threads started by users different from userID. Otherwise just filter on forumid and stickyness.
            if (!canViewNormalThreadsStartedByOthers)
            {
                // caller can't view threads started by others: add a filter so that threads not started by calling user aren't enlisted.
                // however sticky threads are always returned so the filter contains a check so the limit is only applied on threads which aren't sticky
                // add a filter for sticky threads, add it with 'OR', so sticky threads are always accepted. The whole expression is and-ed to the already existing
                // expression
                q.AndWhere((ThreadFields.StartedByUserID.Equal(userId)).Or(ThreadFields.IsSticky.Equal(true)));
            }

            using (var adapter = new DataAccessAdapter())
            {
                var toReturn = await adapter.FetchQueryAsync(q).ConfigureAwait(false);

                return(toReturn);
            }
        }
Пример #26
0
        /// <summary>
        /// Modifies the given properties of the given thread.
        /// </summary>
        /// <param name="threadId">The threadID of the thread which properties should be changed</param>
        /// <param name="subject">The new subject for this thread</param>
        /// <param name="isSticky">The new value for IsSticky</param>
        /// <param name="isClosed">The new value for IsClosed</param>
        public static async Task ModifyThreadPropertiesAsync(int threadId, string subject, bool isSticky, bool isClosed)
        {
            var thread = await ThreadGuiHelper.GetThreadAsync(threadId);

            if (thread == null)
            {
                // not found
                return;
            }

            // update the fields with new values
            thread.Subject  = subject;
            thread.IsSticky = isSticky;
            thread.IsClosed = isClosed;
            using (var adapter = new DataAccessAdapter())
            {
                await adapter.StartTransactionAsync(IsolationLevel.ReadCommitted, "ModifyThreadProperties");

                try
                {
                    var result = await adapter.SaveEntityAsync(thread).ConfigureAwait(false);

                    if (result)
                    {
                        // save succeeded, so remove from queue, pass the current transaction to the method so the action takes place inside this transaction.
                        await SupportQueueManager.RemoveThreadFromQueueAsync(threadId, adapter);
                    }

                    adapter.Commit();
                }
                catch
                {
                    adapter.Rollback();
                    throw;
                }
            }
        }
Пример #27
0
        /// <summary>
        /// Does the search using MS Full text search
        /// </summary>
        /// <param name="searchString">Search string.</param>
        /// <param name="forumIDs">Forum Ids of forums to search into.</param>
        /// <param name="orderFirstElement">Order first element setting.</param>
        /// <param name="orderSecondElement">Order second element setting.</param>
        /// <param name="forumsWithThreadsFromOthers">The forums with threads from others.</param>
        /// <param name="userID">The userid of the calling user.</param>
        /// <param name="targetToSearch">The target to search.</param>
        /// <returns>
        /// TypedList filled with threads matching the query.
        /// </returns>
        public static SearchResultTypedList DoSearch(string searchString, List <int> forumIDs, SearchResultsOrderSetting orderFirstElement,
                                                     SearchResultsOrderSetting orderSecondElement, List <int> forumsWithThreadsFromOthers, int userID, SearchTarget targetToSearch)
        {
            // the search utilizes full text search. It performs a CONTAINS upon the MessageText field of the Message entity.
            string searchTerms       = PrepareSearchTerms(searchString);
            bool   searchMessageText = (targetToSearch == SearchTarget.MessageText) || (targetToSearch == SearchTarget.MessageTextAndThreadSubject);
            bool   searchSubject     = (targetToSearch == SearchTarget.ThreadSubject) || (targetToSearch == SearchTarget.MessageTextAndThreadSubject);

            if (!(searchSubject || searchMessageText))
            {
                // no target specified, select message
                searchMessageText = true;
            }

            PredicateExpression searchTermFilter = new PredicateExpression();

            if (searchMessageText)
            {
                // Message contents filter
                searchTermFilter.Add(new FieldCompareSetPredicate(ThreadFields.ThreadID, MessageFields.ThreadID,
                                                                  SetOperator.In, new FieldFullTextSearchPredicate(MessageFields.MessageText, FullTextSearchOperator.Contains, searchTerms)));
            }
            if (searchSubject)
            {
                // Thread subject filter
                if (searchMessageText)
                {
                    searchTermFilter.AddWithOr(new FieldFullTextSearchPredicate(ThreadFields.Subject, FullTextSearchOperator.Contains, searchTerms));
                }
                else
                {
                    searchTermFilter.Add(new FieldFullTextSearchPredicate(ThreadFields.Subject, FullTextSearchOperator.Contains, searchTerms));
                }
            }
            IPredicateExpression mainFilter = searchTermFilter
                                              .And(ForumFields.ForumID == forumIDs)
                                              .And(ThreadGuiHelper.CreateThreadFilter(forumsWithThreadsFromOthers, userID));

            ISortExpression sorter = new SortExpression();

            // add first element
            sorter.Add(CreateSearchSortClause(orderFirstElement));
            if (orderSecondElement != orderFirstElement)
            {
                sorter.Add(CreateSearchSortClause(orderSecondElement));
            }

            SearchResultTypedList results = new SearchResultTypedList(false);

            try
            {
                // get the data from the db.
                results.Fill(500, sorter, false, mainFilter);
            }
            catch
            {
                // probably an error with the search words / user error. Swallow for now, which will result in an empty resultset.
            }

            return(results);
        }
Пример #28
0
        /// <summary>
        /// Retrieves for all available sections all forums with all relevant statistical information. This information is stored per forum in an
        /// AggregatedForumRow instance. The forum instances are indexed under their sectionid. Only forums which are vieable by the user are returned.
        /// </summary>
        /// <param name="availableSections">SectionCollection with all available sections</param>
        /// <param name="accessableForums">List of accessable forums IDs.</param>
        /// <param name="forumsWithThreadsFromOthers">The forums for which the calling user can view other users' threads. Can be null</param>
        /// <param name="userId">The userid of the calling user.</param>
        /// <returns>
        /// MultiValueHashtable with per key (sectionID) a set of AggregatedForumRow instance, one row per forum in the section. If a section contains no forums
        /// displayable to the user it's not present in the returned hashtable.
        /// </returns>
        public static async Task <MultiValueHashtable <int, AggregatedForumRow> > GetAllAvailableForumsAggregatedData(EntityCollection <SectionEntity> availableSections,
                                                                                                                      List <int> accessableForums,
                                                                                                                      List <int> forumsWithThreadsFromOthers, int userId)
        {
            var toReturn = new MultiValueHashtable <int, AggregatedForumRow>();

            // return an empty list, if the user does not have a valid list of forums to access
            if (accessableForums == null || accessableForums.Count <= 0)
            {
                return(toReturn);
            }

            // fetch all forums with statistics in a dynamic list, while filtering on the list of accessable forums for this user.
            // Create the filter separate of the query itself, as it's re-used multiple times.
            var threadFilter = ThreadGuiHelper.CreateThreadFilter(forumsWithThreadsFromOthers, userId);

            var qf = new QueryFactory();
            var q  = qf.Create()
                     .Select(() => new AggregatedForumRow()
            {
                ForumID              = ForumFields.ForumID.ToValue <int>(),
                ForumName            = ForumFields.ForumName.ToValue <string>(),
                ForumDescription     = ForumFields.ForumDescription.ToValue <string>(),
                ForumLastPostingDate = ForumFields.ForumLastPostingDate.ToValue <DateTime?>(),

                // add a scalar query which retrieves the # of threads in the specific forum.
                // this will result in the query:
                // (
                //		SELECT COUNT(ThreadID) FROM Thread
                //		WHERE ForumID = Forum.ForumID AND threadfilter.
                // ) As AmountThreads
                AmountThreads = qf.Create()
                                .Select(ThreadFields.ThreadID.Count())
                                .CorrelatedOver(ThreadFields.ForumID.Equal(ForumFields.ForumID))
                                .Where(threadFilter)
                                .ToScalar().As("AmountThreads").ToValue <int>(),

                // add a scalar query which retrieves the # of messages in the threads of this forum.
                // this will result in the query:
                // (
                //		SELECT COUNT(MessageID) FROM Message
                //		WHERE ThreadID IN
                //		(
                //			SELECT ThreadID FROM Thread WHERE ForumID = Forum.ForumID AND threadfilter
                //		)
                // ) AS AmountMessages
                AmountMessages = qf.Create()
                                 .Select(MessageFields.MessageID.Count())
                                 .Where(MessageFields.ThreadID.In(
                                            qf.Create()
                                            .Select(ThreadFields.ThreadID)
                                            .CorrelatedOver(ThreadFields.ForumID.Equal(ForumFields.ForumID))
                                            .Where(threadFilter)))
                                 .ToScalar().As("AmountMessages").ToValue <int>(),
                HasRSSFeed = ForumFields.HasRSSFeed.ToValue <bool>(),
                SectionID  = ForumFields.SectionID.ToValue <int>()
            })
                     .Where(ForumFields.ForumID.In(accessableForums))
                     .OrderBy(ForumFields.OrderNo.Ascending(), ForumFields.ForumName.Ascending())
                     .CacheResultset(Globals.DefaultCacheDurationOfResultsets);

            using (var adapter = new DataAccessAdapter())
            {
                var results = await adapter.FetchQueryAsync(q).ConfigureAwait(false);

                foreach (var forum in results)
                {
                    toReturn.Add(forum.SectionID, forum);
                }
            }

            return(toReturn);
        }
Пример #29
0
        /// <summary>
        /// Sends email to all users subscribed to a specified thread, except the user who initiated the thread update.
        /// </summary>
        /// <param name="threadId">The thread that was updated.</param>
        /// <param name="initiatedByUserId">The user who initiated the update (who will not receive notification).</param>
        /// <param name="emailData">The email data.</param>
        private static async Task SendThreadReplyNotifications(int threadId, int initiatedByUserId, Dictionary <string, string> emailData)
        {
            // get list of subscribers to thread, minus the initiator. Do this by fetching the subscriptions plus the related user entity entity instances.
            // The related user entities are loaded using a prefetch path.
            var q = new QueryFactory().ThreadSubscription
                    .Where((ThreadSubscriptionFields.ThreadID.Equal(threadId)).And(ThreadSubscriptionFields.UserID.NotEqual(initiatedByUserId)))
                    .WithPath(ThreadSubscriptionEntity.PrefetchPathUser);
            var subscriptions = new EntityCollection <ThreadSubscriptionEntity>();

            using (var adapter = new DataAccessAdapter())
            {
                await adapter.FetchQueryAsync(q, subscriptions).ConfigureAwait(false);

                if (subscriptions.Count <= 0)
                {
                    // no subscriptions, nothing to do
                    return;
                }
            }

            // now collect all email addresses into an array so we can pass that to the email routine.
            var toAddresses = new string[subscriptions.Count];

            for (var i = 0; i < subscriptions.Count; i++)
            {
                toAddresses[i] = subscriptions[i].User.EmailAddress;
            }

            // use template to construct message to send.
            var emailTemplate = emailData.GetValue("emailTemplate") ?? string.Empty;
            var mailBody      = SD.HnD.Utility.StringBuilderCache.Acquire(emailTemplate.Length + 256);

            mailBody.Append(emailTemplate);
            var applicationURL = emailData.GetValue("applicationURL") ?? string.Empty;

            if (!string.IsNullOrEmpty(emailTemplate))
            {
                // Use the existing template to format the body
                var siteName = emailData.GetValue("siteName") ?? string.Empty;
                var thread   = await ThreadGuiHelper.GetThreadAsync(threadId);

                if (thread == null)
                {
                    // thread doesn't exist, exit
                    return;
                }

                var threadSubject = thread.Subject;
                var threadUrl     = string.Format("{0}Thread/{1}", applicationURL, thread.ThreadID);
                mailBody.Replace("[SiteURL]", applicationURL);
                mailBody.Replace("[SiteName]", siteName);
                mailBody.Replace("[ThreadSubject]", threadSubject);
                mailBody.Replace("[ThreadURL]", threadUrl);
            }

            // format the subject
            var subject     = (emailData.GetValue("emailThreadNotificationSubject") ?? string.Empty);
            var fromAddress = emailData.GetValue("defaultFromEmailAddress") ?? string.Empty;

            try
            {
                //send message
                await HnDGeneralUtils.SendEmail(subject, SD.HnD.Utility.StringBuilderCache.GetStringAndRelease(mailBody), fromAddress, toAddresses, emailData)
                .ConfigureAwait(false);
            }
            catch (SmtpFailedRecipientsException)
            {
                // swallow as it shouldn't have any effect on further operations
            }
            catch (SmtpException)
            {
                // swallow, as there's nothing we can do
            }
            catch (SmtpCommandException)
            {
                // recipient didn't exist, forget it.
            }

            // rest: problematic, so bubble upwards.
        }
Пример #30
0
        /// <summary>
        /// Returns a DataView object that contains a complete list of threads list for
        /// the requested forum and required date & time interval
        /// </summary>
        /// <param name="forumID">ID of Forum for which the Threadlist is required</param>
        /// <param name="limiter">Limits the Threadlist to between now and; last 48 Hrs, Last Week, Last Month, Last Year</param>
        /// <param name="minNumberOfThreadsToFetch">The minimum number of threads to fetch if there are less threads available in the limiter interval</param>
        /// <param name="minNumberOfNonStickyVisibleThreads">The minimum number of non-sticky visible threads to show. If the # of threads is lower than
        /// this number (due to the limiter value), the minNumberOfThreadsToFetch are fetched</param>
        /// <param name="canViewNormalThreadsStartedByOthers">If set to true, the user calling the method has the right to view threads started by others.
        /// Otherwise only the threads started by the user calling the method are returned.</param>
        /// <param name="userID">The userid of the user calling the method.</param>
        /// <returns>DataView with all the threads</returns>
        public static DataView GetAllThreadsInForumAsDataView(int forumID, ThreadListInterval limiter, short minNumberOfThreadsToFetch,
                                                              short minNumberOfNonStickyVisibleThreads, bool canViewNormalThreadsStartedByOthers, int userID)
        {
            DateTime limiterDate;

            // convert the limiter enum to a datetime which we can use in the filters on the thread data, where we'll use the limiter date
            // as a filter for the last posting date of a post in a given thread.
            switch (limiter)
            {
            case ThreadListInterval.Last24Hours:
                limiterDate = DateTime.Today.AddHours(-24);
                break;

            case ThreadListInterval.Last48Hours:
                limiterDate = DateTime.Today.AddHours(-48);
                break;

            case ThreadListInterval.LastWeek:
                limiterDate = DateTime.Today.AddDays(-7);
                break;

            case ThreadListInterval.LastMonth:
                limiterDate = DateTime.Today.AddMonths(-1);
                break;

            case ThreadListInterval.LastYear:
                limiterDate = DateTime.Today.AddYears(-1);
                break;

            default:
                limiterDate = DateTime.Today.AddHours(-48);
                break;
            }

            var qf = new QueryFactory();
            var q  = qf.Create();

            q.Select(ThreadGuiHelper.BuildQueryProjectionForAllThreadsWithStats(qf));
            q.From(ThreadGuiHelper.BuildFromClauseForAllThreadsWithStats(qf));
            q.Where(((ThreadFields.IsSticky == true).Or(ThreadFields.ThreadLastPostingDate >= limiterDate)).And(ThreadFields.ForumID == forumID));
            // if the user can't view threads started by others, filter out threads started by users different from userID
            if (!canViewNormalThreadsStartedByOthers)
            {
                // caller can't view threads started by others: add a filter so that threads not started by calling user aren't enlisted.
                // however sticky threads are always returned so the filter contains a check so the limit is only applied on threads which aren't sticky
                // add a filter for sticky threads, add it with 'OR', so sticky threads are always accepted
                q.AndWhere((ThreadFields.StartedByUserID == userID).Or(ThreadFields.IsSticky == true));
            }
            q.OrderBy(ThreadFields.IsSticky.Descending(), ThreadFields.IsClosed.Ascending(), ThreadFields.ThreadLastPostingDate.Descending());
            var dao     = new TypedListDAO();
            var threads = dao.FetchAsDataTable(q);

            // count # non-sticky threads. If it's below a given minimum, refetch everything, but now don't fetch on date filtered but at least the
            // set minimum. Do this ONLY if the user can view other user's threads. If that's NOT the case, don't refetch anything.
            DataView stickyThreads = new DataView(threads, ThreadFieldIndex.IsSticky.ToString() + "=false", "", DataViewRowState.CurrentRows);

            if ((stickyThreads.Count < minNumberOfNonStickyVisibleThreads) && canViewNormalThreadsStartedByOthers)
            {
                // not enough threads available, fetch again,
                // first fetch the sticky threads.
                q = qf.Create();
                q.Select(ThreadGuiHelper.BuildQueryProjectionForAllThreadsWithStats(qf));
                q.From(ThreadGuiHelper.BuildFromClauseForAllThreadsWithStats(qf));
                q.Where((ThreadFields.IsSticky == true).And(ThreadFields.ForumID == forumID));
                q.OrderBy(ThreadFields.ThreadLastPostingDate.Descending());
                threads = dao.FetchAsDataTable(q);

                // then fetch the rest. Fetch it into the same datatable object to append the rows to the already fetched sticky threads (if any)
                q = qf.Create();
                q.Select(ThreadGuiHelper.BuildQueryProjectionForAllThreadsWithStats(qf));
                q.From(ThreadGuiHelper.BuildFromClauseForAllThreadsWithStats(qf));
                q.Where((ThreadFields.IsSticky == false).And(ThreadFields.ForumID == forumID));
                q.Limit(minNumberOfThreadsToFetch);
                q.OrderBy(ThreadFields.ThreadLastPostingDate.Descending());
                dao.FetchAsDataTable(q, threads);

                // sort closed threads to the bottom. Do this in-memory as it's a sort operation after projection. Doing it on the server would mean
                // a sort operation before projection.
                return(new DataView(threads, string.Empty, ThreadFieldIndex.IsClosed.ToString() + " ASC", DataViewRowState.CurrentRows));
            }
            else
            {
                return(threads.DefaultView);
            }
        }