Discord.NET better way of comparing roles - c#

So in my Discord bot, I am creating a full moderation system where users with appropriate privileges may hand out warnings to other users, these will be recorded, once 3 warnings are hit, the user is muted for a set time, this can occur 5 times for which they are muted for longer periods of time, after the fifth mute when the user reaches 3 more warnings, they are banned permanently. So I have pretty much made the whole thing which was no issue with a history viewer of users etc, but the problem I am having is with comparing roles. I have found a solution that I am not sure if it works properly in the long run, but was the only method I could think of. I want it to not allow users to warn those with higher ranks than themselves. This is the code I have for it:
public class Warn : ModuleBase<SocketCommandContext>
{
[Command("Warn")]
public async Task WarnMain([Remainder, Summary("Warn a user for a reason.")] IGuildUser user, string warnInfo)
{
var userRole = -1;
var victimRole = -1;
var counter = 0;
foreach(var role in Context.Guild.Roles)
{
if (Context.Guild.GetUser(Context.User.Id).Roles.Contains(role) && userRole == -1)
{
userRole = counter;
}
if (Context.Guild.GetUser(user.Id).Roles.Contains(role) && victimRole == -1)
{
victimRole = counter;
}
}
if (userRole < victimRole)
// blah blah
}
}
If you know of a better way or more efficient way of doing this, please share, would be much appreciated. Thanks.

First off, I would like to point out that discord.py has their own method of comparing between permissions. You could try to run their python script in your C# code, or 'translate' it from python into C#. You can check out their source code for comparing between permissions here.
For me personally, since my bot is not really made for moderation, I took the lazy way out and made a simple function that compares permissions using nested if-else statements.
private static bool PermissionComparison(GuildPermissions targetGuildPerms, GuildPermissions userGuildPerms)
{
//True if the target has a higher role.
bool targetHasHigherPerms = false;
//If the user is not admin but target is.
if(!userGuildPerms.Administrator && targetGuildPerms.Administrator) {
//The target has higher permission than the user.
targetHasHigherPerms = true;
} else if(!userGuildPerms.ManageGuild && targetGuildPerms.ManageGuild) {
targetHasHigherPerms = true;
} else if(!userGuildPerms.ManageChannels && targetGuildPerms.ManageChannels) {
targetHasHigherPerms = true;
} else if(!userGuildPerms.BanMembers && targetGuildPerms.BanMembers) {
targetHasHigherPerms = true;
} else if(!userGuildPerms.KickMembers && targetGuildPerms.KickMembers) {
targetHasHigherPerms = true;
}
return targetHasHigherPerms;
}
I would personally suggest using other methods instead if they seem better.

It seems the way I did it is the only way to actually compare roles as far as I can tell. Spent the last 4 hours looking for alternatives but did not come across anything.
My method is simply going through each role and comparing, I believe the API already sorts the roles from highest first to lowest last. You can then use a counter to compare the numbers at which the highest role is found that is assigned the the user.
Comparing permissions doesn't always work, especially in my case, therefore I could not use that method either. This seems to work best for me. If anyone has anything better feel free to share, I'd love to see how I can improve it.

If you cast the user to a SocketGuilderUser then you can compare the Hierarchy property.
Its basically the same thing you are already doing just avoids looping through the roles.

Related

How can I specify which value a enum can have based on the current value?

I am looking for a way to specify a lets call it Decision Tree or a Flow.
I have a Start value 1 or REQUESTED and this enum can have multiple following values like 2 or IN_PROGRESS or 3 or DECLINED.
And now only from the value 2 it should be possible to go to a higher value like 4 or FINISHED.
What is the most practically way to define the possible paths a process or flow can have?
What's practical is often what's easiest to read an understand. To that end I recommend being explicit about what which states can lead to which other states. The enum is just a list of possible values. Using the int values of the enum might seem more concise, but it's harder to read and can lead to other problems.
First, here's an enum and a simple class that changes from one state to another if that change is allowed. (I didn't cover every state.)
enum RequestState
{
Requested,
InProgress,
Declined,
Finished
}
public class Request
{
private RequestState _state = RequestState.Requested;
public void BeginWork()
{
if (_state == RequestState.Declined || _state == RequestState.Finished)
throw new InvalidOperationException("You can only begin work on a new request.");
_state = RequestState.InProgress;
}
public void Decline()
{
if (_state == RequestState.Finished)
throw new InvalidOperationException("Too late - it's finished!");
_state = RequestState.Declined;
}
// etc.
}
If we base it on the numeric value of _state and determine that the number can only go up, a few things can go wrong:
Someone can rearrange the enums or add a new one, not knowing that the numeric value or position has logical significance. That's an easy mistake because that value usually isn't significant.
You might need to implement logic that isn't quite so simple. You might need a state that can be preceded by some of the values before it but not all of them.
You might realize that there's a valid reason for going backwards. What if a request is declined, and in the future you determine that you want to reopen requests, effectively sending them back to Requested?
If the way this is implemented starts out a little bit weird, those changes could make it even harder to change and follow. But if you just describe clearly what changes are possible given any state then it will be easy to read and modify.
You could do something to leverage that enums are basically just integers:
private static Status NextState(Status status)
{
var intOfStatus = ((int)status) + 1;
return (Status)intOfStatus;
}
And some sample logic based on this approach:
public enum Status
{
NotStarted = 0,
Started = 1,
InProgress = 2,
Declined = 3
}
public static void Main()
{
var curStatus = Status.NotStarted;
Console.WriteLine(curStatus.ToString()); //writes 'NotStarted'
if ((int)curStatus++ == (int)Status.Started)
{
curStatus = Status.Started;
}
Console.WriteLine(NextState(curStatus)); //writes 'InProgress'
}

Get Current loggedIn UserID

I want to get the Current loggedin UserID of the user without using Membership How can I achieve that ?
Here is my code
string CurrentlyLoggedInUser = Session["User"].ToString(); // get the userId for username and compare
string userId = CurrentlyLoggedInUser; // assign the userid here and check ok
if (Id == userId)
{
ScriptManager.RegisterStartupScript(this, this.GetType(), "alert", "alert('You cannot delete yourself');window.location ='AdduserProfile.aspx';", true);
return;
}
But I am not getting the ID. Please help
Values from Session
if (dt != null && dt.Rows.Count > 0)
{
if (dt.Rows[0]["usertype"].ToString() == "0") //SuperAdmin
{
Session["UserType"] = "0";
Session["User"] = dt.Rows[0]["username"].ToString();
Response.Redirect("csrdashboards.aspx");
}
else if (dt.Rows[0]["usertype"].ToString() == "1") // Admin
{
Session["UserType"] = "1";
Session["User"] = dt.Rows[0]["username"].ToString();
Response.Redirect("csrdashboards.aspx");
}
else if (dt.Rows[0]["usertype"].ToString() == "2") // User
{
Session["UserType"] = "2";
Session["User"] = dt.Rows[0]["username"].ToString();
Response.Redirect("csrdashboards.aspx");
}
}
I want to get the Current loggedin UserID of the user without using
Membership How can I achieve that ?
Don't.
Look, I know that Membership isn't a shining example of the very best in API design. I know there are things that I personally would have done differently, as would many others, and there can be a strong temptation to roll your own membership API.
But if you're not 100% confident of your ability to do a better job, don't even try. Security infrastructure is too important and too easy to get wrong, and there's a dangerously high likelihood that you'll get something wrong and leave your site vulnerable.
I don't want to put anybody down, but looking at the quality of the code you've posted (code duplication, unnecessary assignments, multiple dictionary lookups, unnecessary-looking conversions to string all over the place) and some of the statements you're making (about having a "password" field in your database with no mention of hashing), you are not yet at the level of ability required for this, and you're heading for disaster.
"How do I...?" is the wrong question here. "Should I...?" is the first question you should ask, and I'm afraid the answer is no. Use Membership, it's not perfect but it's going to be a lot more secure and robust than anything you come up with yourself.

Delay in Active Directory user creation when using System.DirectoryServices.AccountManagement

I am creating accounts and setting properties on them using System.DirectoryServices.AccountManagement in .NET 4.5. One of the requirements is that the group membership (including Primary Group) be copied from a template account. The code includes the following:
foreach (var group in userPrincipal.GetGroups()) {
var groupPrincipal = (GroupPrincipal) #group;
if (groupPrincipal.Sid != templatePrimaryGroup.Sid) {
groupPrincipal.Members.Remove(userPrincipal);
groupPrincipal.Save();
}
}
This works about 90% of the time. The rest of the time, it fails with:
System.DirectoryServices.DirectoryServicesCOMException was
unhandled HResult=-2147016656 Message=There is no such object on
the server.
Source=System.DirectoryServices ErrorCode=-2147016656
ExtendedError=8333 ExtendedErrorMessage=0000208D: NameErr:
DSID-03100213, problem 2001 (NO_OBJECT), data 0, best match of:
'OU=Whatever,DC=domain,DC=local`
on the GetGroups call. My guess is that there is a race condition of some sort with the user not being fully created before I next go to access it. I know from diagnostic logging that I am going against the same domain controller each time (it's using the same PrincipalContext so that matches my expectation) so it's not a replication issue.
Is my guess accurate? Is there a good way to handle this? I could just throw in a Sleep but that seems like a cop-out at best and fragile at worst. So what is the right thing to do?
Try something like:
int maxWait = 120;
int cnt = 0;
bool usable = false;
while (usable == false && cnt < maxWait)
{
try
{
foreach (var group in userPrincipal.GetGroups())
{
var groupPrincipal = (GroupPrincipal)#group;
if (groupPrincipal.Sid != templatePrimaryGroup.Sid)
{
groupPrincipal.Members.Remove(userPrincipal);
groupPrincipal.Save();
}
}
usable = true;
break;
}
catch
{
System.Threading.Thread.Sleep(500);
}
}
if (usable)
//All okay
;
else
//Do something
;
This way you can try for "a while". If it works good, if not do something like log an error, so you can run a fix-it script later.

designing application classes

Besides using the Single Responsibility Principle, when designing classes for an application one is writing, what should one keep in mind, to keep the code maintainable, reusable and adhere to OOP principles?
I'm finding it hard to design the classes of applications I'm trying to write, because when does one decide what (functionality) goes in which class and whether it should really be in a derived class or there should be an abstract class or interface for this class?
I know this is probably a topic with many answers, but does anyone have any good guidelines (preferably simple) to designing classes and class hierarchies that are simple to maintain and don't make a mess when creating big applications?
EDIT:
When there's classes that have 10 methods and over and have an abstract base class & interfaces which it derives from. Also has 3 Singleton classes referenced globally inside the class and much more. Sounds like it needs a bit of 'refactoring' applied?
Sorry if it's a long example, but you see the problem I'm facing and I want some input on it. Please just look at design, not at technicalities.
I give an example:
I created this class: (a while back)
class ExistingUserLogon : Logon, ILogonUser
{
#region Member Variables
LogonEventArgs _logoneventargs;
LogonData lgndata;
Factory f = Factory.FactoryInstance;
PasswordEncrypt.Collections.AppLoginDataCollection applogindatacollection;
PasswordEncrypt.Collections.SQlLoginDataCollection sqllogindatacollection;
bool? compare;
static ExistingUserLogon existinguserlogon;
PasswordEncrypt.SQLDatabase.DatabaseLogin dblogin;
string databasename = string.Empty;
#endregion
#region Properties
public static ExistingUserLogon ExistingUserLogonInstance
{
get
{
if (existinguserlogon == null)
existinguserlogon = new ExistingUserLogon();
return existinguserlogon;
}
}
public string loginname
{
get;
set;
}
#endregion
#region Contructors
public ExistingUserLogon(bool? compare, LogonData logondata)
{
this.compare = compare;
this.lgndata = logondata;
this.applogindatacollection = f.AppLoginDataCollection;
this.sqllogindatacollection = f.SqlLoginDataCollection;
}
public ExistingUserLogon()
{
this.applogindatacollection = f.AppLoginDataCollection;
this.sqllogindatacollection = f.SqlLoginDataCollection;
}
#endregion
#region Delegates
public delegate void ConnStrCreated( object sender, LogonEventArgs e );
#endregion
#region Events
public event ConnStrCreated ConnectionStringCreated;
#endregion
private void OnConnectionStringCreated( object sender, LogonEventArgs e )
{
if (ConnectionStringCreated != null)
{
ConnectionStringCreated(sender, e);
}
}
public void LoginNewUser()
{
dblogin = new PasswordEncrypt.SQLDatabase.DatabaseLogin();
if (!string.IsNullOrEmpty(loginname))
{
string temp = dblogin.GenerateDBUserName(loginname);
if (temp != "Already Exists")
{
if (compare == true)
{
IterateCollection(lgndata.HahsedUserName.HashedUserName, new Action<string>(OnDatabaseName));
IterateCollection(temp, new Action<bool, string, string>(OnIterateSuccess));
}
}
}
else
{
LogonEventArgs e = new LogonEventArgs();
e.Success = false;
e.ErrorMessage = "Error! No Username";
OnError(this, e);
}
}
private void OnDatabaseName(string name)
{
this.databasename = name;
}
private void OnIterateSuccess( bool succeed, string psw, string userid )
{
if (succeed)
{
// Create connectionstring
ConnectionStringCreator cnstrCreate = ConnectionStringCreator.ConnectionStringInstance;
if (databasename != string.Empty)
{
string conn = ConnectionStringCreator.CreateConnString(databasename, userid, psw);
bool databaseExists;
databaseExists = DataManagementVerification.DoDatabaseExists(conn);
if (databaseExists)
{
FormsTransfer.ConnectionString = conn;
conn = string.Empty;
}
else
{
LogonEventArgs e = new LogonEventArgs();
e.Success = false;
e.ErrorMessage = "Database does not Exist!";
OnError(this, e);
}
//OnConnectionStringCreated(this, e);
// PasswordEncrypt.LINQtoSQL.PasswordDatabase db = new PasswordEncrypt.LINQtoSQL.PasswordDatabase(conn);
/* PasswordEncrypt.LINQtoSQL.EncryptData _encryptdata = new PasswordEncrypt.LINQtoSQL.EncryptData()
{
EncryptID = 1,
IV = "Test",
PrivateKey = "Hello",
PublicKey = "Tony"
};
db.EncryptionData.InsertOnSubmit(_encryptdata);
// db.SubmitChanges();*/
//PasswordEncrypt.LINQtoSQL.Data _data = new PasswordEncrypt.LINQtoSQL.Data()
//{
// EncryptionID = 1,
// Username = "Tbone",
// Password = "worstje",
// IDCol = 2
//};
//db.Data.InsertOnSubmit(_data);
//db.SubmitChanges();
//IEnumerable<PasswordEncrypt.LINQtoSQL.Data> _ddata = db.Data.Where(data => data.Password == "worstje"); ;
//foreach (PasswordEncrypt.LINQtoSQL.Data data in _ddata)
//{
// MessageBox.Show("Data Found: " + data.Username + "," + data.Password);
//}
}
else
{
MessageBox.Show("Found no Database name", "Database name error");
}
}
else
{
// Unable to create connectionstring
}
}
private void IterateCollection( string username, Action<bool, string, string> OnSucceed )
{
bool succeed = false;
dblogin = new PasswordEncrypt.SQLDatabase.DatabaseLogin();
string psw;
string userid;
foreach (KeyValuePair<PasswordEncrypt.Collections.GItem<string>, PasswordEncrypt.Collections.GItem<string>> kv in sqllogindatacollection)
{
List<char> tempa = new List<char>();
List<char> tempb = new List<char>();
tempa = dblogin.GetNumber(username);
tempb = dblogin.GetNumber(kv.Key.Item);
if (tempa.Count == tempb.Count)
{
for (int i = 0; i < tempa.Count ; i++)
{
if (tempa.ElementAt(i).Equals(tempb.ElementAt(i)))
{
if ( i == (tempa.Count -1) )
succeed = true;
continue;
}
else
{
KeyValuePair<PasswordEncrypt.Collections.GItem<string>, PasswordEncrypt.Collections.GItem<string>> last = sqllogindatacollection.Last();
if (kv.Key.Item.Equals(last.Key.Item))
{
MessageBox.Show("Failed to match usernames for Database", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
succeed = false;
// Let GUI Know...
LogonEventArgs e = new LogonEventArgs();
e.Success = succeed;
OnError(this, e);
break;
}
else
{
break;
}
}
}
// MessageBox.Show("Found a sql username match");
}
// Now go execute method to logon into database...
if (succeed)
{
psw = kv.Value.Item;
userid = kv.Key.Item;
OnSucceed(succeed, psw, userid);
}
succeed = false;
}
}
private void IterateCollection(string key, Action<string> OnDatabaseName )
{
foreach (KeyValuePair<PasswordEncrypt.Collections.GItem<string>, PasswordEncrypt.Collections.GItem<string>> kv in applogindatacollection)
{
if (key == kv.Key.Item)
{
MessageBox.Show("Found a match");
OnDatabaseName(kv.Value.Item);
}
else
{
// MessageBox.Show("No Match");
}
}
}
#region Public Methods
public bool? ReadFromRegistry( HashedUsername username, HashedPassword hashedpassword )
{
return RegistryEdit.ReadFromRegistry(username, hashedpassword);
}
public bool WriteToRegistry( HashedUsername username, HashedPassword hashedpassword )
{
return RegistryEdit.WriteToRegistry(username, hashedpassword);
}
public override void Login(TextBox username, TextBox password)
{
base.Login(username, password);
Login(username.Text, password.Text);
}
protected override void Login(string username, string password)
{
base.Login(username, password);
lgndata = base._logondata;
compare = base._regRead;
if (compare == true)
{
loginname = username;
LoginNewUser();
/// on login succeeded let UI class know
_logoneventargs = new LogonEventArgs();
_logoneventargs.Success = true;
OnExistingUserLoggedIn(this, _logoneventargs);
}
else
{
_logoneventargs = new LogonEventArgs();
_logoneventargs.Success = false;
_logoneventargs.ErrorMessage = "Cannot Login this user, please try again.";
OnError(this, _logoneventargs);
}
/// Get username and password for database...
/// to login using correct user data & permissions
/// Login data for database is generated at runtime
/// then by checking if database with such a name exists
/// login...
}
#endregion
}
Hear I post some of sentence that I did take from my favorite book "Architecting Microsoft® .NET Solutions for the Enterprise" that I strongly recommend to read this book even if you’re not a Software Architect.
It Depends
It always depends. As an architect, you are never sure about anything. There's always the possibility that you're missing something. However, the role requires that decisions be made, so you must be able to evaluate all options and make an informed decision, and to do this promptly, when a decision is required. To buy yourself some time and activate your mental processes in the background, first say, "It depends," and then explain why and what the answer depends on. If you are unsure about what a point depends on, the default answer is, "It depends on the context."
Requirements Are Lord Over All
The architect is just one link in the natural chain of actors in a software project. The customer says what he wants. If the customer doesn't know what he wants, someone will be there to prompt him for specifics. The analyst formalizes what the customer wants. The project manager prepares the groundwork for the formally-defined project. The architect gets the bundle of requirements and sorts them out. Developers follow the architect. The database administrator does his best to make the database support the application effectively. Note that the customer leads the chain, and what the customer wants is the law. What the customer wants goes under the name of requirements. Of course, only few customers know what it is they want. So requirements change.
Program to an Interface
Even if you make a living out of implemented code, you should leverage interfaces wherever possible. Repeat with us: "No implementation is possible without an interface." Look around, there's always an interface that can be extracted.
Keep It Simple but Not Simplistic
You know KISS (Keep It Simple, Stupid), right? This is just our customized version. Simple and concise is usually equivalent to great and well done. Aim at simplicity, but give yourself a boundary for the low end of the range. If you go below that lower boundary, your solution will become simplistic. And this is not a good thing.
Inheritance Is About Polymorphism, Not Reuse
Object-oriented programming (OOP) taught us that we should write a class once and reuse it forever and extend it at will. And this is possible thanks to inheritance. Does this naturally extend to class reuse? Reuse is a much subtler concept than you might think at first. Polymorphism is the key aspect of OOP to leverage. Polymorphism means you can use two inherited classes interchangeably. As others have said, "Reuse is a nice side effect to have." But reuse shouldn't be your goal, or put another way, don't reuse a class through inheritance just to reuse the class. It's better to write a new class that more precisely fits the needs than to try to inherit an existing class that wasn't designed for the job.
Not the DAL? Don't Touch SQL Then
Repeat with us: "Separation of concerns. Separation of concerns." Push data access code and details (such as connection strings, commands, and table names) to the corner. Sooner or later, you need to take care of them, but consider business and presentation logic separately from persistence. And if possible, delegate persistence to ad hoc tools such as Object/ Relational Mapper (O/RM) tools.
Maintainability First
If you could pick only one attribute for your software, what would it be? Scalability? Security? Performance? Testability? Usability? For us, it would be none of the above. For us, what comes first is maintainability. Through maintainability, you can achieve anything else at any time.
All User Input Is Evil
You should have heard this already. If there's a way for users to do something wrong, they'll find it. Oh, this sounds like Murphy's Law. Yes, you should have heard this one, too, already.
Post-Mortem Optimization
Donald Knuth said that premature optimization is the root of all software evil. We go even further. Do not optimize the system. Instead, design it for being improved and extended at any time. But focus on pure optimization only when the system is dismissed.
Security and Testability Are by Design
If you're serious about a system attribute, design for it right from the beginning. Security and testability are no exception to this rule, and there's an International Organization for Standardization (ISO) standard that specifically says so.
I hope you this will help you.
Well, aside from keeping the code maintainable, reusable, and adhering to OOP principles... :)
I'd be careful to avoid paralysis of analysis here: if you don't make the right choice between a class, derived class, or interface, for example, that's what refactoring is for. In fact, I'd argue that's the whole point of principles like the SRP - not to make it easy to design everything beforehand, but to make it easy to change things as your requirements grow and change shape, because you can't predict everything beforehand.
A tension exists between designing code to be reusable and just creating something that is usable. Design for reuse where you can, but don't let that get in the way of just implementing the requirements that are right in front of you.
One tip I've heard (courtesy of Spolsky, probably) is: when you need perform an operation in one place, write the code. When you need to perform it in another place, write the code again. When you want to perform the same op in a third place, now it's time to think about refactoring.
Don't try to design a vast, all-encompassing system in the hopes of avoiding change - design code that's resilient to change.
One thing I wish I learned early was to design your code to interact through very simple interfaces rather than massive APIs. I would recommend you even do this internally. Create simple interfaces that interact between your modules. This makes testing SO much easier.
private interface IPerformWork
{
void DoThis(String value);
void DoThat(String value);
}
Remember, the less coupled your code is the better.
Code Smells
Why don't you browse through this question. It may not be C# specific but a lot of it is completely language agnostic.
https://stackoverflow.com/questions/114342/what-are-code-smells-what-is-the-best-way-to-correct-them
There is a good question here on Stackoverflow that discusses C# anti-patterns, and how to avoid them.
You should give it a quick read through; it exposes a lot of things that you may be tempted to do/not realize are wrong, and has suggestions for how to accomplish the same functionality in a more elegant way.
This is one of those things that they rarely teach in schools, and even when they do its usually a contrived example that still doesnt give you a good idea of how to do it.
The bottom line is that there really isnt a good concrete, scientific way to do this, after all computer programming is still very much an art. :)
What I like to do is:
Write a brief outline of what the application is suppose to do, high level stuff in bullet point form
Divide the bullet points up into "required", "optional", "nice-to-have". Where "required" is stuff that must be there to even "demo" and optional is the stuff that basically makes it a complete application in the customers eyes
If required do my drawings, diagrams, UML, specs etc at this point (depends on whats required)
Start writing code. I like to draft out what I am doing in code and start figuring out how things lay out and what functionality needs to be where
Work to an initial prototype (the "required" stuff) once I reach this point I freeze and start looking at where the design is at, and what the feedback is
Start prioritizing refactoring and redesign with fixing issues in the prototype.
Refactor! Redesign and reimplement
Rinse, lather and repeat.
For some things its obvious what goes into which objects, which classes are needed and what designs are working well. For other things it takes an iteration or two to work out the bugs.
I learn something new on ever project, and I find new ways to apply concepts I thought I understood well. Its a constant learning experience, and there is always something to learn.

How to check if a another user is on the same or lower level in the company hierarchy?

I've got this:
UserProfile prof = getUserProfile(properties.CurrentUserId);
UserProfile toCheck = getUserProfile(anotherUsersId);
"prof" user must be on a higher or on the same level as "toCheck" user. If "toCheck" is on a lower level he/she must be on the same branch of the hierarchy tree. If they are on the same level, their manager must be the same.
Is there an easy way to check this?
There are a few methods that should help you here:
GetPeers
GetManagers
GetDirectReports
There is no "easy way" that I've found but you can write your own helper classes that use these methods, traverse the user profiles, and find the information you need.
As an aside: "Colleagues" is not related to this. They are a list of people that, with a complete My Site implementation, users can manage themselves.
Some pseudo code:
function compare(manager, toCheck, prof)
{
toManager=toCheck.manager;
if (toManager!=null)
{
if (manager==tomanager || prof==tomanager)
{
return true;
}
else
{
return compare("", tomanager, prof);
}
}
else // he/she is the boss
{
return false;
}
}
...
if (prof.manager!=null)
{
compare(prof.manager, toCheck, prof);
}
else // he/she is the boss
{
return true;
}

Categories