public Operation <BitLevel> Demote(string userRef, int units, string haxh) => _authorizer.AuthorizeAccess(this.PermissionProfile(UserContext.CurrentUser()), () => { Haxher.IsValidHash(haxh).ThrowIf(_v => !_v, "Access Denied"); var @ref = _refQuery.GetReferalNode(userRef); var targetUser = new User { EntityId = @ref.UserId }; var currentLevel = _query.CurrentBitLevel(targetUser).ThrowIfNull("User has not begun cycling"); var newLevel = BitCycle.Create(currentLevel.Cycle, currentLevel.Level).Decrement(units); currentLevel.Cycle = newLevel.Cycle; currentLevel.Level = newLevel.Level; _pcommand.Update(currentLevel); currentLevel.Donation.Amount = GetUpgradeAmount(newLevel.Level + 1); _pcommand.Update(currentLevel.Donation); //move all current donnors to the next available beneficiary _query.GetDonorLevels(targetUser) .Where(_lvl => newLevel > new BitCycle { Cycle = _lvl.Cycle, Level = _lvl.Level }) .Select(_lvl => { var nextLevel = new BitCycle { Cycle = _lvl.Cycle, Level = _lvl.Level }.Increment(1); var beneficiary = NextUpgradeBeneficiary(targetUser, nextLevel.Level, nextLevel.Cycle); var address = _query.GetActiveBitcoinAddress(beneficiary); _lvl.Donation.ReceiverId = address.Id; return(_pcommand.Update(_lvl.Donation)); }) .ThrowIf(_ops => !_ops.Any(_op => _op.Succeeded), "failed to reassign some donors"); return(currentLevel); });
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); })); } });