public List <ITextChatMessage> GetHistory(RoomId roomId, List <Enumerables.MessageVisibility> withVisibilities, int messageCount)
        {
            using (var db = new HellolingoEntities())
            {
                // [Replaced by a SPROC call to try to improve perf issues]
                var entityResult = db.TextChats.AsNoTracking()
                                   .OrderByDescending(a => a.ID)
                                   .Where(a => a.RoomId == roomId && withVisibilities.Any(b => (byte)b == a.Visibility))
                                   // THIS NEXT LINE IS CRITICAL!!!! NOT USING MAKES THE QUERY WAY SLOWER, TO THE POINT THAT IT BRINGS
                                   // THE SERVER DOWN WHEN THE IIS APPLICATION POOL IS RECYCLED AND ALL USERS ARE RELOADING ALL THEIR ROOMS.
                                   // EF ACTUALLY LOADS THE FULL DEFINITION OF THE USER WHEN ToList IS CALLED... WHICH WILL CLEARLY TAKE A WHOLE LOT OF TIME.
                                   .Select(a => new { a.ID, a.When, a.UserId, a.FirstName, a.RoomId, a.Text, a.Visibility })
                                   .Take(messageCount).ToList().OrderBy(a => a.ID);

                //var entityResult = db.TextChat_GetHistory(messageCount, roomId, string.Join(",", withVisibilities.Cast<int>()));

                return(entityResult.Select(
                           msg => (ITextChatMessage) new TextChatMessage {
                    When = msg.When,
                    UserId = msg.UserId,
                    FirstName = msg.FirstName,
                    RoomId = msg.RoomId,
                    Text = msg.Text,
                    Visibility = (Enumerables.MessageVisibility)msg.Visibility
                }).OrderBy(msg => msg.When).ToList());
            }
        }
Beispiel #2
0
        public void AddMessageTest()
        {
            var storage = new TextChatDbStorage();
            var message = new TextChatMessage
            {
                UserId     = 1,
                FirstName  = "Bernard",
                LastName   = "V",
                RoomId     = "english",
                Text       = "AddMessageTest = Hello World!",
                Visibility = MessageVisibility.Everyone,
                DeviceTag  = 0
            };

            storage.AddMessageAsync(message);

            // check last message
            DataAccess.TextChat savedMessage;
            using (var db = new HellolingoEntities())
            {
                savedMessage = db.TextChats.OrderByDescending(a => a.ID).FirstOrDefault();
            }

            Assert.IsNotNull(savedMessage);
            Assert.AreEqual(message.When, savedMessage.When);
            // ReSharper disable once PossibleInvalidOperationException
            Assert.AreEqual(message.UserId, new UserId(savedMessage.UserId.Value));
            Assert.AreEqual(0, savedMessage.DeviceTag, "DeviceTag must be null");
            Assert.AreEqual(message.FirstName, savedMessage.FirstName);
            Assert.AreEqual(message.RoomId.ToString(), savedMessage.RoomId);
            Assert.AreEqual(message.Text, savedMessage.Text);
            Assert.AreEqual((byte)message.Visibility, savedMessage.Visibility);
        }
        public List <IPrivateChatStatus> GetPrivateChatStatuses(int userId)
        {
            using (var db = new HellolingoEntities())
            {
                var entityResult = db.TextChatTrackers.AsNoTracking()
                                   .OrderByDescending(a => a.StatusAt)
                                   .Where(a => a.UserId == userId && a.Status != TrackerStatus.AutoBlocked)
                                   .Select(a => new { a.Status, a.StatusAt, a.Partner })     // IMPORTANT LINE: It prevents EF from having to load all related data (e.g. users, statuses details, etc...)
                                   .ToList();

                return(entityResult.Select(
                           status => (IPrivateChatStatus) new PrivateChatStatus {
                    Partner = new TextChatUser {
                        FirstName = status.Partner.FirstName,
                        Id = status.Partner.Id,
                        LastName = status.Partner.LastName,
                        Country = status.Partner.CountryId,
                        Location = status.Partner.Location,
                        Gender = status.Partner.Gender,
                        Age = AgeInYearsHelper.GetAgeFrom(status.Partner.BirthYear, status.Partner.BirthMonth),
                        Knows = status.Partner.KnowsId,
                        Learns = status.Partner.LearnsId,
                        Knows2 = status.Partner.Knows2Id,
                        Learns2 = status.Partner.Learns2Id
                    },
                    StatusId = status.Status,
                    StatusAt = status.StatusAt
                }).ToList());
            }
        }
Beispiel #4
0
 public IEnumerable <ListedUser> List(ListRequest request)
 {
     using (HellolingoEntities db = new HellolingoEntities())
     {
         int?tag = null;
         if (request.IsSharedTalkMember)
         {
             tag = UserTags.FormerSharedTalkMember;
         }
         if (request.IsLivemochaMember)
         {
             tag = UserTags.LivemochaMember;
         }
         if (request.IsSharedLingoMember)
         {
             tag = UserTags.SharedLingoMember;
         }
         IEnumerable <ListedUser> listedMembers = db.ListedUsers_GetBy(
             count: null, belowId: request.BelowId,
             knows: request.KnownId, learns: request.LearnId,
             firstName: request.FirstName, lastName: request.LastName,
             country: null, location: null,
             minAge: null, maxAge: null,
             tag: tag
             ).ToList();
         return(listedMembers);
     }
 }
        //public string LocalUserCulture => User.Identity.GetClaims().UserCulture;

        public async Task <User> GetLocalUser()
        {
            using (var db = new HellolingoEntities()) {
                var localUserId = LocalUserId;
                return(await db.Users.AsNoTracking().Include(u => u.Status).FirstOrDefaultAsync(u => u.Id == localUserId));
            }
        }
 public async Task LinkDeviceToUser(long deviceTag, int userId)
 {
     // Store in database
     using (var db = new HellolingoEntities()) {
         db.UsersDevices.AddOrUpdate(new UsersDevice {
             DeviceTag = deviceTag, UserId = userId, LastIPV4 = 0L
         });
         await db.SaveChangesAsync();
     }
 }
Beispiel #7
0
        // DISCLAIMER: THIS IS NOT A PROPER UNIT TEST
        // It accesses the database
        // It relies on pre-populated data in that database
        // But it's a good demo
        public void MailboxSprocsTest()
        {
            var userId1 = 1;
            var userId2 = 2;
            var db      = new HellolingoEntities();

            // Insert a new mail (that User1 sends to user2)
            db.Mails_Insert(
                regulationStatus: MailRegulationStatuses.AutoPass,                 // This means that the regulation has cleared this message: No manual step / moderation required
                fromId: userId1,                                                   // Who send the mail
                replyToMail: null,                                                 // Defines to which mailId this mail a directly reply to, if any
                toId: userId2,                                                     // Who receives the mail
                subject: null,                                                     // Subject can be ignored. It will be filled with the beginning of the message.
                message: "Hello, This is a mail demo. Bye bye!"
                );

            // Check that user1 has the sent message in his mailbox
            var mailFor1 = db.Mails_GetList(userId1).FirstOrDefault();             // The right message should be the first one, because the list is ordered with latest first

            Assert.AreEqual(userId1, mailFor1.FromId);
            Assert.AreEqual("true", mailFor1.Lead);             // Lead = true: It means that this message is the latest one of all the messages sent between user1 and user2
            Assert.AreEqual(null, mailFor1.ReplyToMail);
            Assert.AreEqual(MailStatuses.Sent, mailFor1.Status);
            Assert.AreEqual("Hello, This is a mail demo. Bye bye!", mailFor1.Subject);             // Subject should be the first 100 characters of message
            Assert.AreEqual(userId2, mailFor1.ToId);

            // Check that user2 has the received message in his mailbox
            var mailFor2 = db.Mails_GetList(userId2).FirstOrDefault();             // The right message should be the first one, because the list is ordered with latest first

            Assert.AreEqual(userId1, mailFor2.FromId);
            Assert.AreEqual("true", mailFor2.Lead);             // Lead = true: It means that this message is the latest one of all the messages sent between user1 and user2
            Assert.AreEqual(null, mailFor2.ReplyToMail);
            Assert.AreEqual(MailStatuses.New, mailFor2.Status);
            Assert.AreEqual("Hello, This is a mail demo. Bye bye!", mailFor2.Subject);             // Subject should be the first 100 characters of message
            Assert.AreEqual(userId2, mailFor2.ToId);

            // Archive users emails
            var mails = db.Mails_GetList(userId1).ToList();

            foreach (var mail in mails)
            {
                db.Mails_Archive(userId1, mail.Id);
            }
            mails = db.Mails_GetList(userId2).ToList();
            foreach (var mail in mails)
            {
                db.Mails_Archive(userId2, mail.Id);
            }

            // Get the list for user1. It should be empty b/c all mails have been archived
            mails = db.Mails_GetList(userId1).ToList();
            Assert.AreEqual(0, mails.Count(r => r.Status != MailStatuses.Archived));
        }
Beispiel #8
0
        public async Task <PublicUser> GetProfile(GetProfileRequest request)
        {
            using (HellolingoEntities db = new HellolingoEntities()) {
                User foundUser = await db.Users.FindAsync(request.Id);

                if (foundUser == null)
                {
                    Log.Error(LogTag.UserNotFoundForGetProfileRequest, Request, new { request });
                    return(null);
                }
                return(new PublicUser(foundUser));
            }
        }
 /// <summary>
 ///     Constructor which takes a db context and wires up the stores with default instances using the context
 /// </summary>
 /// <param name="context"></param>
 public ApplicationUserStore(HellolingoEntities context)
 {
     if (context == null)
     {
         throw new ArgumentNullException("context");
     }
     Context         = context;
     AutoSaveChanges = true;
     _userStore      = new EntityStore <AspNetUser>(context);
     _roleStore      = new EntityStore <AspNetRole>(context);
     _logins         = Context.Set <AspNetUserLogin>( );
     _userClaims     = Context.Set <AspNetUserClaim>( );
     //_userRoles = Context.Set<AspNetRole>( );
 }
 public async Task AddMessageAsync(ITextChatMessage msg)
 {
     using (var db = new HellolingoEntities()) {
         var record = new DataAccess.TextChat {
             When       = msg.When,
             RoomId     = msg.RoomId,
             UserId     = msg.UserId,
             DeviceTag  = msg.DeviceTag,
             FirstName  = msg.FirstName,
             LastName   = msg.LastName,
             Text       = msg.Text,
             Visibility = (byte)msg.Visibility,
         };
         db.TextChats.Add(record);
         await db.SaveChangesAsync();
     }
 }
        public static async Task <Result <bool> > JoinRoom(User user, RoomId roomId)
        {
            var result = Result <bool> .True;

            if (!roomId.IsPrivate())
            {
                return(result);
            }

            int userIdEf = user.Id; string roomIdEf = roomId;             // Casting named types into their base type because EF doesn't get it otherwise.
            int partnerId = ChatModel.PartnerIdFrom(roomId, user.Id);

            using (var db = new HellolingoEntities()) {
                var userTracker    = db.TextChatTrackers.Find(userIdEf, roomIdEf);
                var partnerTracker = db.TextChatTrackers.Find(partnerId, roomIdEf);

                // Handle people directly joining by the url from outside the chat
                if (userTracker == null || partnerTracker == null)
                {
                    await RequestPrivateChat(user, roomId, partnerId);

                    result.Reports.AddReport(LogTag.ChatRequestAddedFromJoinRoom, new { userId = user.Id, roomId });
                    return(result);
                }

                // Set new statuses according to current status
                if ((userTracker.Status == TrackerStatus.Invited || userTracker.Status == TrackerStatus.IgnoredInvite) && partnerTracker.Status == TrackerStatus.Inviting)
                {
                    userTracker.Status    = TrackerStatus.AcceptedInvite;
                    partnerTracker.Status = TrackerStatus.InviteAccepted;
                    userTracker.StatusAt  = partnerTracker.StatusAt = DateTime.Now;
                    result.Reports        = new LogReports(LogTag.ChatRequestAccepted);
                }
                else if (userTracker.Status == TrackerStatus.InviteAccepted)
                {
                    userTracker.Status   = TrackerStatus.SeenInviteResponse;
                    userTracker.StatusAt = DateTime.Now;
                }

                await db.SaveChangesAsync();
            }

            return(result);
        }
 private void SaveLastVisit(string userName)
 {
     using (var db = new HellolingoEntities())
     {
         var user = db.Users.FirstOrDefault(u => u.AspNetUser.UserName == userName);
         if (user != null)
         {
             user.LastVisit = DateTime.Now;
         }
         try
         {
             db.SaveChanges();
         }
         catch (Exception e)
         {
             LogError(e);
         }
     }
 }
        public static async Task <Result <bool> > MarkAllCaughtUp(UserId userId, RoomId roomId)
        {
            int userIdEf = userId; string roomIdEf = roomId;             // Casting named types into their base type because EF doesn't get it otherwise.
            var result = Result <bool> .True;

            using (var db = new HellolingoEntities()) {
                var userRecord = db.TextChatTrackers.Find(userIdEf, roomIdEf);
                if (userRecord == null)
                {
                    return(new Result <bool>(false, LogTag.UnexpectedTrackerStatus, new { method = "MarkAllCaughtUp", userId, roomId }, LogLevel.Error));
                }
                if (userRecord.Status == TrackerStatus.AllCaughtUp || userRecord.Status == TrackerStatus.Inviting || userRecord.Status == TrackerStatus.Invited)
                {
                    return(result);
                }
                userRecord.Status   = TrackerStatus.AllCaughtUp;
                userRecord.StatusAt = DateTime.Now;
                await db.SaveChangesAsync();
            }
            return(result);
        }
        public static async Task <Result <bool> > IgnorePrivateChat(UserId userId, RoomId roomId, UserId partnerId)
        {
            int userIdEf = userId, partnerIdEf = partnerId; string roomIdEf = roomId;             // Casting named types into their base type because EF doesn't get it otherwise.

            using (var db = new HellolingoEntities()) {
                var inviterRecord = db.TextChatTrackers.Find(partnerIdEf, roomIdEf);
                var inviteeRecord = db.TextChatTrackers.Find(userIdEf, roomIdEf);

                if (inviterRecord == null || inviteeRecord == null)
                {
                    return(new Result <bool>(false, LogTag.IgnorePrivateChatMissingTrackerRecord, new { userId, roomId, partnerId }, LogLevel.Error));
                }

                // Set record for invitee
                inviteeRecord.Status   = TrackerStatus.IgnoredInvite;
                inviteeRecord.StatusAt = DateTime.Now;
                await db.SaveChangesAsync();
            }

            return(Result <bool> .True);
        }
        public void TestFind()
        {
            var db     = new HellolingoEntities();
            var result = db.ListedUsers_GetBy(
                //Andriy: I made count 100, because test throws exception. I don't know, whether  this exception by intention or not.
                //Bernard: ^ Fixed: Entity Framework doesn't support default values for stored procedure parameters, so enforced it with a check in the stored procedure.
                count: null,
                belowId: null,
                knows: null,
                learns: null,
                firstName: null,
                lastName: null,
                country: null,
                location: null,
                minAge: null,
                maxAge: null,
                tag: null
                );
            var list = result.ToList();

            Assert.AreNotEqual(0, list.Count);
        }
        public static async Task <Result <bool> > PostTo(UserId userId, RoomId roomId)
        {
            var    result    = Result <bool> .True;
            string roomIdEf  = roomId;            // Casting named types into their base type because EF doesn't get it otherwise.
            int    partnerId = ChatModel.PartnerIdFrom(roomId, userId);

            using (var db = new HellolingoEntities()) {
                var partnerRecord = db.TextChatTrackers.Find(partnerId, roomIdEf);
                if (partnerRecord == null)
                {
                    return(new Result <bool>(false, LogTag.UnexpectedTrackerStatus, new { method = "PostTo", userId, roomId }, LogLevel.Error));
                }
                if (partnerRecord.Status == TrackerStatus.Invited || partnerRecord.Status == TrackerStatus.AutoBlocked || partnerRecord.Status == TrackerStatus.DeclinedInvite || partnerRecord.Status == TrackerStatus.IgnoredInvite || partnerRecord.Status == TrackerStatus.UnreadMessages)
                {
                    return(new Result <bool>(true));
                }
                partnerRecord.Status   = TrackerStatus.UnreadMessages;
                partnerRecord.StatusAt = DateTime.Now;
                await db.SaveChangesAsync();
            }
            return(result);
        }
Beispiel #17
0
        public void TestLastVisitUpdated()
        {
            var user = new AspNetUser()
            {
                UserName = "******"
            };
            var filter           = new LastVisitFilter(new LastVisitHelper());
            var filterContext    = new ActionExecutingContext();
            var fakeHttpContext  = new Mock <HttpContextBase>();
            var fakeIdentityMock = new Mock <IIdentity>();

            fakeIdentityMock.Setup(i => i.IsAuthenticated).Returns(true);
            fakeIdentityMock.Setup(i => i.Name).Returns(user.UserName);
            fakeIdentityMock.SetupGet(i => i.Name).Returns(user.UserName);
            fakeHttpContext.SetupGet(t => t.User.Identity).Returns(fakeIdentityMock.Object);
            var controllerContext = new Mock <ControllerContext>();

            controllerContext.Setup(t => t.HttpContext).Returns(fakeHttpContext.Object);
            filterContext.HttpContext = fakeHttpContext.Object;
            DateTime before;
            DateTime after;

            using (HellolingoEntities db = new HellolingoEntities())
            {
                User userBefore = db.Users.FirstOrDefault(u => u.AspNetUser.UserName == user.UserName);
                before = userBefore.LastVisit.Value;
            }

            filter.OnActionExecuting(filterContext);
            using (HellolingoEntities db = new HellolingoEntities())
            {
                User userAfter = db.Users.FirstOrDefault(u => u.AspNetUser.UserName == user.UserName);
                after = userAfter.LastVisit.Value;
            }
            Assert.IsTrue(after > before);
        }
        public async Task TestGetMemberById()
        {
            User userSharedTalk;

            using (var db = new HellolingoEntities())
            {
                userSharedTalk = await db.Users.FindAsync(1);
            }
            var controller = new MemberController();

            controller.User = new GenericPrincipal(new ClaimsIdentity(new Claim [] { new Claim(CustomClaimTypes.UserId, userSharedTalk.Id.ToString()) }), null);

            var foundMember = await controller.GetProfile(new MemberController.GetProfileRequest {
                Id = 1
            });

            Assert.AreEqual(userSharedTalk.Id, foundMember.Id, $"{nameof(foundMember.Id)} is wrong.");
            Assert.AreEqual(userSharedTalk.FirstName, foundMember.FirstName, $"{nameof(foundMember.FirstName)} is wrong.");
            Assert.AreEqual(userSharedTalk.LastName, foundMember.LastName, $"{nameof(foundMember.LastName)} is wrong.");
            Assert.AreEqual(userSharedTalk.CountryId, foundMember.Country, $"{nameof(foundMember.Country)} is wrong.");
            Assert.AreEqual(userSharedTalk.Location, foundMember.Location, $"{nameof(foundMember.Location)} is wrong.");
            Assert.AreEqual(userSharedTalk.KnowsId, foundMember.Knows, $"{nameof(foundMember.Knows)} is wrong.");
            Assert.AreEqual(userSharedTalk.LearnsId, foundMember.Learns, $"{nameof(foundMember.Learns)} is wrong.");
            Assert.AreEqual(userSharedTalk.Introduction, foundMember.Introduction, $"{nameof(foundMember.Introduction)} is wrong.");
            Assert.AreEqual(new DateTime(userSharedTalk.BirthYear, userSharedTalk.BirthMonth, 1).GetAgeInYears(DateTime.Now), foundMember.Age, $"{nameof(foundMember.Age)} is wrong.");
            Assert.IsTrue(foundMember.IsSharedTalkMember);


            User userNewUser;

            using (var db = new HellolingoEntities())
            {
                userNewUser = await db.Users.FindAsync(5870);
            }
            var controller2 = new MemberController();

            controller.User = new GenericPrincipal(new ClaimsIdentity(new Claim [] { new Claim(CustomClaimTypes.UserId, userNewUser.Id.ToString()) }), null);

            var foundMember2 = await controller2.GetProfile(new MemberController.GetProfileRequest {
                Id = 5870
            });

            Assert.AreEqual(userNewUser.Id, foundMember2.Id, $"{nameof(foundMember2.Id)} is wrong.");
            Assert.AreEqual(userNewUser.FirstName, foundMember2.FirstName, $"{nameof(foundMember2.FirstName)} is wrong.");
            Assert.AreEqual(userNewUser.LastName, foundMember2.LastName, $"{nameof(foundMember2.LastName)} is wrong.");
            Assert.AreEqual(userNewUser.CountryId, foundMember2.Country, $"{nameof(foundMember2.Country)} is wrong.");
            Assert.AreEqual(userNewUser.Location, foundMember2.Location, $"{nameof(foundMember2.Location)} is wrong.");
            Assert.AreEqual(userNewUser.KnowsId, foundMember2.Knows, $"{nameof(foundMember2.Knows)} is wrong.");
            Assert.AreEqual(userNewUser.LearnsId, foundMember2.Learns, $"{nameof(foundMember2.Learns)} is wrong.");
            Assert.AreEqual(userNewUser.Introduction, foundMember2.Introduction, $"{nameof(foundMember2.Introduction)} is wrong.");
            Assert.AreEqual(new DateTime(userNewUser.BirthYear, userNewUser.BirthMonth, 1).GetAgeInYears(DateTime.Now), foundMember2.Age, $"{nameof(foundMember2.Age)} is wrong.");
            Assert.IsFalse(foundMember2.IsSharedTalkMember);

            var controller3 = new MemberController();

            try
            {
                await controller3.GetProfile(new MemberController.GetProfileRequest {
                    Id = 0
                });
            }
            catch (HttpException e)
            {
                Assert.AreEqual((int)HttpStatusCode.BadRequest, e.GetHttpCode());
            }
        }
Beispiel #19
0
 public ActionResult MadeByMembers()
 {
     using (var db = new HellolingoEntities())
         ViewBag.membersCount = db.Users.Max(r => r.Id);
     return(PartialView());
 }
        public static async Task <Result <Propagate> > RequestPrivateChat(User user, RoomId roomId, UserId partnerId)
        {
            int partnerIdEf = partnerId; string roomIdEf = roomId;             // Casting named types into their base type because EF doesn't get it otherwise.
            var toStatus  = TrackerStatus.Invited;
            var propagate = true;

            using (var db = new HellolingoEntities()) {
                var inviterRecord = db.TextChatTrackers.Find(user.Id, roomIdEf);
                var inviteeRecord = db.TextChatTrackers.Find(partnerIdEf, roomIdEf);
                var partner       = db.Users.Find(partnerIdEf);

                if (inviterRecord != null || inviteeRecord != null)
                {
                    return(new Result <Propagate>(false, LogTag.RequestPrivateChatHasExistingRecord, new { user.Id, roomId, partnerId }, LogLevel.Error));
                }

                // Check if it's a restricted invite
                var restricted = false;
                var userKnows  = new List <byte?> {
                    user.KnowsId, user.Knows2Id, user.Knows3Id
                };
                var userLearns = new List <byte?> {
                    user.LearnsId, user.Learns2Id, user.Learns3Id
                };
                var isHelper = userKnows.Contains(partner.LearnsId) || (partner.Learns2Id != null && userKnows.Contains(partner.Learns2Id)) || (partner.Learns3Id != null && userKnows.Contains(partner.Learns3Id));

                if (!WhitelistedMembers.Contains(user.Id) && !isHelper)
                {
                    // Reset RestrictedMembers every hour, which allows them to send on restricted invite every hour
                    if (DateTime.Now.Hour != RestrictionResetHour)
                    {
                        RestrictedMembers    = new HashSet <UserId>();
                        RestrictionResetHour = DateTime.Now.Hour;
                    }

                    // Detect if the invite is restricted
                    var partnerKnows = new List <byte?> {
                        partner.KnowsId, partner.Knows2Id, partner.Knows3Id
                    };
                    var partnerLearns = new List <byte?> {
                        partner.LearnsId, partner.Learns2Id, partner.Learns3Id
                    };
                    Func <InviteRule, bool> inviteCheck = control => control.FromGender == user.Gender && control.ToGender == partner.Gender &&
                                                          (control.FromKnows == null || userKnows.Contains(control.FromKnows)) &&
                                                          (control.ToKnows == null || partnerKnows.Contains(control.ToKnows)) &&
                                                          (control.ToLearns == null || partnerLearns.Contains(control.ToLearns));

                    // Mark restricted if it matches pattern of restricted invites
                    if (RestictedInvites.Any(restrict => inviteCheck(restrict)))
                    {
                        restricted = true;
                    }

                    // Mark if users only match on native language
                    if ((userKnows.Contains(partner.KnowsId) || (partner.Knows2Id != null && userKnows.Contains(partner.Knows2Id)) || (partner.Knows3Id != null && userKnows.Contains(partner.Knows3Id))) &&
                        !(userLearns.Contains(partner.KnowsId) || (partner.Knows2Id != null && userLearns.Contains(partner.Knows2Id)) || (partner.Knows3Id != null && userLearns.Contains(partner.Knows3Id))) &&
                        !(userKnows.Contains(partner.LearnsId) || (partner.Learns2Id != null && userKnows.Contains(partner.Learns2Id)) || (partner.Learns3Id != null && userKnows.Contains(partner.Learns3Id))) &&
                        !(userLearns.Contains(partner.LearnsId) || (partner.Learns2Id != null && userLearns.Contains(partner.Learns2Id)) || (partner.Learns3Id != null && userLearns.Contains(partner.Learns3Id)))
                        )
                    {
                        restricted = true;
                    }

                    // Derestrict if whitelisted
                    if (WhitelistedInvites.Any(allow => inviteCheck(allow)))
                    {
                        restricted = false;
                    }

                    // If restricted, block it, unless it's the first one from this user.
                    if (restricted)
                    {
                        if (RestrictedMembers.Contains(user.Id))
                        {
                            toStatus  = TrackerStatus.AutoBlocked;
                            propagate = false;
                        }
                        else
                        {
                            RestrictedMembers.Add(user.Id);
                        }
                    }
                }

                // Set record for inviter
                db.TextChatTrackers.Add(new TextChatTracker {
                    UserId = user.Id, RoomId = roomIdEf, PartnerId = partnerIdEf,
                    Status = TrackerStatus.Inviting, StatusAt = DateTime.Now, Initiator = true
                });

                // Set record for invitee
                db.TextChatTrackers.Add(new TextChatTracker {
                    UserId = partnerIdEf, RoomId = roomIdEf, PartnerId = user.Id,
                    Status = toStatus, StatusAt = DateTime.Now, Initiator = false
                });

                await db.SaveChangesAsync();
            }

            return(new Result <Propagate>(propagate));
        }