public Operation <ReferralNode> AffixNewUser(string userId, string refereeCode) => _authorizer.AuthorizeAccess(UserContext.CurrentProcessPermissionProfile(), () => { //lock because referal placement is not thread safe! lock (UniversalLock) { var referee = _query.GetReferalNode(refereeCode).ThrowIfNull("invalid referee code"); var downlines = _query.AllDownlines(referee); var user = _query.GetUserById(userId); //affix to the referee if he has no downlines if (downlines.Count() == 0) { var @ref = new ReferralNode { UplineCode = refereeCode, ReferrerCode = refereeCode, ReferenceCode = ReferralHelper.GenerateCode(userId), User = user }; return(_pcommand.Add(@ref)); } //generate a map for each downline referal node, with its reference code as key var hierarchyMap = GenerateHierarchyMap(downlines); //calculate and assign levels based on distance from the referee node in the hierarchy hierarchyMap.ForAll((cnt, duo) => duo.Value.Level = DistanceFromReferee(referee, duo.Key, hierarchyMap)); //rearrange and order the downlines, then get the first incomplete duo, and place the new referal in the slot return(hierarchyMap .Values .OrderBy(_duo => _duo.Level) .ThenBy(_duo => _duo.Count) .FirstOrDefault(_duo => _duo.Count < 2) .Pipe(_duo => { var @ref = new ReferralNode { UplineCode = _duo.UplineCode, ReferrerCode = refereeCode, ReferenceCode = ReferralHelper.GenerateCode(userId), User = user }; return _pcommand.Add(@ref); })); } });
private int DistanceFromReferee(ReferralNode referee, string referenceCode, Dictionary <string, DownlineDuo> map) { var count = 1; if (referenceCode == referee.ReferenceCode) { return(count); } else { do { referenceCode = map.Values .FirstOrDefault(_duo => _duo.ContainsNode(referenceCode)) .UplineCode; count++; }while (referenceCode != referee.ReferenceCode); return(count); } }
public IEnumerable <ReferralNode> AllDownlines(ReferralNode node) { var query = @" WITH DownLinesCTE (ReferenceCode, [rank]) AS ( -- Anchor member definition SELECT r.ReferenceCode, 0 FROM dbo.ReferralNode AS r WHERE r.UplineCode = @reference UNION ALL -- Recursive member definition SELECT downline.ReferenceCode, code.[rank] + 1 FROM DownLinesCTE as code JOIN dbo.ReferralNode AS downline ON downline.UplineCode = code.ReferenceCode ) -- Statement that executes the CTE SELECT r.ReferenceCode, r.ReferrerCode, r.UplineCode, r.CreatedOn, r.ModifiedOn, r.Id, u.EntityId AS u_EntityId, u.CreatedOn AS u_CreatedOn, u.ModifiedOn AS u_ModifiedOn, u.Status as u_Status, u.UId AS u_UId, bd.FirstName, bd.LastName, cd.Phone as u_Phone, ud.Data AS u_ProfileImage FROM dbo.ReferralNode AS r JOIN dbo.[User] AS u ON u.EntityId = r.UserId JOIN DownLinesCTE AS dl ON dl.ReferenceCode = r.ReferenceCode LEFT JOIN dbo.BioData AS bd ON bd.OwnerId = u.EntityId LEFT JOIN dbo.ContactData AS cd ON cd.OwnerId = u.EntityId LEFT JOIN dbo.UserData AS ud ON ud.OwnerId = u.EntityId and ud.Name = '" + Constants.UserData_ProfileImage + @"' ORDER BY dl.[rank] "; using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["EuropaContext"].ConnectionString)) { connection.Open(); var qcommand = new SqlCommand { Connection = connection, CommandText = query, //CommandTimeout = }; qcommand.Parameters.Add(new SqlParameter("reference", node.ReferenceCode)); using (var row = qcommand.ExecuteReader()) { var refnodes = new List <ReferralNode>(); var userCache = new Dictionary <string, User>(); while (row.Read()) { refnodes.Add(new ReferralNode { ReferenceCode = row.IsDBNull(0) ? null : row.GetString(0), ReferrerCode = row.IsDBNull(1) ? null : row.GetString(1), UplineCode = row.IsDBNull(3) ? null : row.GetString(2), CreatedOn = row.GetDateTime(3), ModifiedOn = row.IsDBNull(4) ? (DateTime?)null : row.GetDateTime(4), Id = row.GetInt64(5), User = userCache.GetOrAdd(row.GetString(6), _uid => new User //<-- the UserId of the ReferralNode is also set behind the scenes { EntityId = _uid, CreatedOn = row.GetDateTime(7), ModifiedOn = row.IsDBNull(8) ? (DateTime?)null : row.GetDateTime(8), Status = row.GetInt32(9), UId = row.GetGuid(10) }), UserBio = !hasBio(row)? null: new BioData { FirstName = row.IsDBNull(11) ? null : row.GetString(11), LastName = row.IsDBNull(12) ? null : row.GetString(12) }, UserContact = row.IsDBNull(13) ? null : new ContactData { Phone = row.GetString(13) } }); } return(refnodes); } } }
public Operation <IEnumerable <ReferralNode> > Uplines(ReferralNode node) => _authorizer.AuthorizeAccess(UserContext.CurrentProcessPermissionProfile(), () => { return(_query.Uplines(node)); });
public IEnumerable <ReferralNode> DirectDownlines(ReferralNode node) => _europa.Store <ReferralNode>() .QueryWith(_r => _r.User) .Where(_r => _r.UplineCode == node.ReferenceCode) .ToArray();