/// <summary> /// Copies the properties from another AttendanceCode object to this AttendanceCode object /// </summary> /// <param name="target">The target.</param> /// <param name="source">The source.</param> public static void CopyPropertiesFrom(this AttendanceCode target, AttendanceCode source) { target.IssueDateTime = source.IssueDateTime; target.Code = source.Code; target.Id = source.Id; target.Guid = source.Guid; }
/// <summary> /// Returns a new <see cref="Rock.Model.AttendanceCode"/> /// </summary> /// <param name="codeLength">A <see cref="System.Int32"/> representing the length of the (security) code.</param> /// <returns>A new <see cref="Rock.Model.AttendanceCode"/></returns> public AttendanceCode GetNew(int codeLength = 3) { string code = string.Empty; var attendanceCode = new AttendanceCode(); // Make sure only one instance at a time is checking for unique code lock (obj) { // Find a good unique code for today while (code == string.Empty || noGood.Any(s => s == code) || Get(DateTime.Today, code).Any()) { code = GenerateRandomCode(codeLength); } attendanceCode.IssueDateTime = DateTime.Now; attendanceCode.Code = code; this.Add(attendanceCode, null); this.Save(attendanceCode, null); } return(attendanceCode); }
/// <summary> /// Gets the new. /// </summary> /// <param name="alphaNumericLength">Length of the alpha numeric.</param> /// <param name="alphaLength">Length of the alpha.</param> /// <param name="numericLength">Length of the numeric.</param> /// <param name="isRandomized">if set to <c>true</c> [is randomized].</param> /// <returns></returns> public static AttendanceCode GetNew(int alphaNumericLength, int alphaLength, int numericLength, bool isRandomized) { lock ( _obj ) { using (var rockContext = new Rock.Data.RockContext()) { var service = new AttendanceCodeService(rockContext); DateTime today = RockDateTime.Today; if (_todaysCodes == null || !_today.HasValue || !_today.Value.Equals(today)) { _today = today; DateTime tomorrow = today.AddDays(1); _todaysCodes = service.Queryable().AsNoTracking() .Where(c => c.IssueDateTime >= today && c.IssueDateTime < tomorrow) .Select(c => c.Code) .ToList(); } // Find a good alphanumeric code prefix string alphaNumericCode = string.Empty; if (alphaNumericLength > 0 || alphaLength > 0) { alphaNumericCode = (alphaNumericLength > 0 ? GenerateRandomCode(alphaNumericLength) : string.Empty) + (alphaLength > 0 ? GenerateRandomAlphaCode(alphaLength) : string.Empty); while (noGood.Any(s => alphaNumericCode.Contains(s)) || _todaysCodes.Contains(alphaNumericCode)) { alphaNumericCode = (alphaNumericLength > 0 ? GenerateRandomCode(alphaNumericLength) : string.Empty) + (alphaLength > 0 ? GenerateRandomAlphaCode(alphaLength) : string.Empty); } } string numericCode = string.Empty; if (numericLength > 0) { int codeLen = alphaNumericLength + alphaLength + numericLength; var lastCode = _todaysCodes.Where(c => c.Length == codeLen).OrderBy(c => c.Substring(alphaNumericLength + alphaLength)).LastOrDefault(); numericCode = GetNextNumericCodeAsString(alphaNumericLength, alphaLength, numericLength, isRandomized, lastCode); } string code = alphaNumericCode + numericCode; _todaysCodes.Add(code); var attendanceCode = new AttendanceCode(); attendanceCode.IssueDateTime = RockDateTime.Now; attendanceCode.Code = code; service.Add(attendanceCode); rockContext.SaveChanges(); return(attendanceCode); } } }
/// <summary> /// Clones this AttendanceCode object to a new AttendanceCode object /// </summary> /// <param name="source">The source.</param> /// <param name="deepCopy">if set to <c>true</c> a deep copy is made. If false, only the basic entity properties are copied.</param> /// <returns></returns> public static AttendanceCode Clone(this AttendanceCode source, bool deepCopy) { if (deepCopy) { return(source.Clone() as AttendanceCode); } else { var target = new AttendanceCode(); target.CopyPropertiesFrom(source); return(target); } }
/// <summary> /// Clones this AttendanceCode object to a new AttendanceCode object with default values for the properties in the Entity and Model base classes. /// </summary> /// <param name="source">The source.</param> /// <returns></returns> public static AttendanceCode CloneWithoutIdentity(this AttendanceCode source) { var target = new AttendanceCode(); target.CopyPropertiesFrom(source); target.Id = 0; target.Guid = Guid.NewGuid(); target.ForeignKey = null; target.ForeignId = null; target.ForeignGuid = null; return(target); }
/// <summary> /// Returns a new <see cref="Rock.Model.AttendanceCode"/> comprised of random alpha numeric characters. /// </summary> /// <param name="codeLength">A <see cref="System.Int32"/> representing the length of the (security) code.</param> /// <returns>A new <see cref="Rock.Model.AttendanceCode"/></returns> public static AttendanceCode GetNew(int codeLength = 3) { lock ( _obj ) { using (var rockContext = new Rock.Data.RockContext()) { var service = new AttendanceCodeService(rockContext); DateTime today = RockDateTime.Today; if (_todaysCodes == null || !_today.HasValue || !_today.Value.Equals(today)) { _today = today; DateTime tomorrow = today.AddDays(1); _todaysCodes = service.Queryable().AsNoTracking() .Where(c => c.IssueDateTime >= today && c.IssueDateTime < tomorrow) .Select(c => c.Code) .ToList(); } // Find a good unique code for today string code = GenerateRandomCode(codeLength); while (noGood.Any(s => s == code) || _todaysCodes.Any(c => c == code)) { code = GenerateRandomCode(codeLength); } _todaysCodes.Add(code); var attendanceCode = new AttendanceCode(); attendanceCode.IssueDateTime = RockDateTime.Now; attendanceCode.Code = code; service.Add(attendanceCode); rockContext.SaveChanges(); return(attendanceCode); } } }
/// <summary> /// Returns a new <see cref="Rock.Model.AttendanceCode" /> with a specified number of alpha characters followed by /// another specified number of numeric characters. The numeric character sequence will not repeat for "today" so /// ensure that you're using a sufficient numericLength otherwise it will be unable to find a unique number. /// Also note as the issued numeric codes reaches the maximum (from the set of possible), it will take longer and /// longer to find an unused number. /// </summary> /// <param name="alphaLength">A <see cref="System.Int32"/> representing the length of the (alpha) portion of the code.</param> /// <param name="numericLength">A <see cref="System.Int32"/> representing the length of the (digit) portion of the code.</param> /// <param name="isRandomized">A <see cref="System.Boolean"/> that controls whether or not the AttendanceCodes should be generated randomly or in order (starting from the smallest).</param> /// <returns> /// A new <see cref="Rock.Model.AttendanceCode" /> /// </returns> public static AttendanceCode GetNew(int alphaLength = 2, int numericLength = 4, bool isRandomized = true) { lock ( _obj ) { using (var rockContext = new Rock.Data.RockContext()) { var service = new AttendanceCodeService(rockContext); DateTime today = RockDateTime.Today; if (_todaysCodes == null || !_today.HasValue || !_today.Value.Equals(today)) { _today = today; DateTime tomorrow = today.AddDays(1); _todaysCodes = service.Queryable().AsNoTracking() .Where(c => c.IssueDateTime >= today && c.IssueDateTime < tomorrow) .Select(c => c.Code) .ToList(); } // Find a good alpha code string alphaCode = GenerateRandomAlphaCode(alphaLength); while (noGood.Any(s => s == alphaCode)) { alphaCode = GenerateRandomAlphaCode(alphaLength); } // Find a good unique numeric code for today string numericCode = string.Empty; if (isRandomized) { numericCode = GenerateRandomNumericCode(numericLength); while (noGood.Any(s => s == numericCode) || _todaysCodes.Any(c => c.EndsWith(numericCode))) { numericCode = GenerateRandomNumericCode(numericLength); } } else { var lastCode = _todaysCodes.OrderBy(c => c.Substring(alphaLength)).LastOrDefault(); if (lastCode != null) { var maxCode = lastCode.Substring(alphaLength); numericCode = (maxCode.AsInteger() + 1).ToString("D" + numericLength); } else { numericCode = 0.ToString("D" + numericLength); } } string code = alphaCode + numericCode; _todaysCodes.Add(code); var attendanceCode = new AttendanceCode(); attendanceCode.IssueDateTime = RockDateTime.Now; attendanceCode.Code = code; service.Add(attendanceCode); rockContext.SaveChanges(); return(attendanceCode); } } }
/// <summary> /// Returns a new <see cref="Rock.Model.AttendanceCode" />. The code will contain the specified number of alphanumeric characters, /// followed by the alpha characters and then the specified number of numeric characters. The character sequence will not repeat for "today". /// Also the numeric character sequence will not repeat for "today". In both cases ensure that you're using a sufficient length for each /// otherwise there will not be enough possible codes. /// Also note as the issued numeric codes reaches the maximum (from the set of possible), it will take longer and /// longer to find an unused number. So specifing a larger number of characters then needed will increase performance. /// </summary> /// <param name="alphaNumericLength">A <see cref="System.Int32"/> representing the length for a mixed alphanumberic code.</param> /// <param name="alphaLength">A <see cref="System.Int32"/> representing the length of the (alpha) portion of the code.</param> /// <param name="numericLength">A <see cref="System.Int32"/> representing the length of the (digit) portion of the code.</param> /// <param name="isRandomized">A <see cref="System.Boolean"/> that controls whether or not the AttendanceCodes should be generated randomly or in order (starting from the smallest). Only effect the numeric code.</param> /// <returns></returns> public static AttendanceCode GetNew(int alphaNumericLength, int alphaLength, int numericLength, bool isRandomized) { lock ( _obj ) { using (var rockContext = new Rock.Data.RockContext()) { var service = new AttendanceCodeService(rockContext); DateTime today = RockDateTime.Today; if (_todaysUsedCodes == null || !_todaysDate.HasValue || !_todaysDate.Value.Equals(today)) { _todaysDate = today; DateTime tomorrow = today.AddDays(1); _todaysUsedCodes = new HashSet <string>(service.Queryable().AsNoTracking().Where(c => c.IssueDateTime >= today && c.IssueDateTime < tomorrow).Select(c => c.Code).ToList()); } string alphaNumericCode = string.Empty; string alphaCode = string.Empty; string numericCode = string.Empty; string code = string.Empty; string lastCode = string.Empty; for (int attempts = 0; attempts <= _maxAttempts; attempts++) { if (attempts == _maxAttempts) { throw new TimeoutException("Too many attempts to create a unique attendance code. There is almost certainly a check-in system 'Security Code Length' configuration problem."); } if (alphaNumericLength > 0) { alphaNumericCode = GenerateRandomCode(alphaNumericLength); } if (alphaLength > 0) { alphaCode = GenerateRandomAlphaCode(alphaLength); } if (numericLength > 0) { int codeLen = alphaNumericLength + alphaLength + numericLength; if (lastCode.IsNullOrWhiteSpace()) { lastCode = _todaysUsedCodes.Where(c => c.Length == codeLen).OrderBy(c => c.Substring(alphaNumericLength + alphaLength)).LastOrDefault(); } numericCode = GetNextNumericCodeAsString(alphaNumericLength, alphaLength, numericLength, isRandomized, lastCode); } code = alphaNumericCode + alphaCode + numericCode; // Check if code is already in use or contains bad unallowed strings. if (noGood.Any(s => code.Contains(s)) || _todaysUsedCodes.Contains(code)) { lastCode = numericCode; alphaNumericCode = string.Empty; alphaCode = string.Empty; numericCode = string.Empty; code = string.Empty; continue; } // When using a clustered environment we need to check the DB to make sure the code hasn't been assigned by another server if (Rock.Utility.Settings.RockInstanceConfig.IsClustered) { if (service.IsCodeAlreadyInUse(code)) { lastCode = numericCode; alphaNumericCode = string.Empty; alphaCode = string.Empty; numericCode = string.Empty; code = string.Empty; continue; } } // If we get to this point the code can be used break; } _todaysUsedCodes.Add(code); var attendanceCode = new AttendanceCode(); attendanceCode.IssueDateTime = RockDateTime.Now; attendanceCode.Code = code; service.Add(attendanceCode); rockContext.SaveChanges(); return(attendanceCode); } } }
/// <summary> /// Gets the new. /// </summary> /// <param name="alphaNumericLength">Length of the alpha numeric.</param> /// <param name="alphaLength">Length of the alpha.</param> /// <param name="numericLength">Length of the numeric.</param> /// <param name="isRandomized">if set to <c>true</c> [is randomized].</param> /// <returns></returns> public static AttendanceCode GetNew(int alphaNumericLength, int alphaLength, int numericLength, bool isRandomized) { lock ( _obj ) { using (var rockContext = new Rock.Data.RockContext()) { var service = new AttendanceCodeService(rockContext); DateTime today = RockDateTime.Today; if (_todaysCodes == null || !_today.HasValue || !_today.Value.Equals(today)) { _today = today; DateTime tomorrow = today.AddDays(1); _todaysCodes = new HashSet <string>(service.Queryable().AsNoTracking() .Where(c => c.IssueDateTime >= today && c.IssueDateTime < tomorrow) .Select(c => c.Code) .ToList()); } // Find a good alphanumeric code prefix string alphaNumericCode = string.Empty; int attempts = 0; if (alphaNumericLength > 0 || alphaLength > 0) { alphaNumericCode = (alphaNumericLength > 0 ? GenerateRandomCode(alphaNumericLength) : string.Empty) + (alphaLength > 0 ? GenerateRandomAlphaCode(alphaLength) : string.Empty); while (noGood.Any(s => alphaNumericCode.Contains(s)) || _todaysCodes.Contains(alphaNumericCode)) { attempts++; // We're only going to attempt this 1 million times... // Interestingly, even when this code approaches the maximum number of possible combinations // it still typically takes less than 5000 attempts. However, if the number of // attempts jumps over 10,000 there is almost certainly a problem with someone's // check-in code configuration so we're going to stop after a million attempts. if (attempts > 1000000) { throw new TimeoutException("Too many attempts to create a unique attendance code. There is almost certainly a check-in system 'Security Code Length' configuration problem."); } alphaNumericCode = (alphaNumericLength > 0 ? GenerateRandomCode(alphaNumericLength) : string.Empty) + (alphaLength > 0 ? GenerateRandomAlphaCode(alphaLength) : string.Empty); } } string numericCode = string.Empty; if (numericLength > 0) { int codeLen = alphaNumericLength + alphaLength + numericLength; var lastCode = _todaysCodes.Where(c => c.Length == codeLen).OrderBy(c => c.Substring(alphaNumericLength + alphaLength)).LastOrDefault(); numericCode = GetNextNumericCodeAsString(alphaNumericLength, alphaLength, numericLength, isRandomized, lastCode); } string code = alphaNumericCode + numericCode; _todaysCodes.Add(code); var attendanceCode = new AttendanceCode(); attendanceCode.IssueDateTime = RockDateTime.Now; attendanceCode.Code = code; service.Add(attendanceCode); rockContext.SaveChanges(); return(attendanceCode); } } }