651 lines
26 KiB
C#
651 lines
26 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Xml;
|
|
using System.IO;
|
|
using System.Windows.Forms;
|
|
using System.Drawing;
|
|
using System.Security.Cryptography;
|
|
using System.Security.Cryptography.Xml;
|
|
|
|
namespace EduNetworkBuilder
|
|
{
|
|
public class PersonClass
|
|
{
|
|
public string filepath=""; //the path of the file. We use the username as the file-name.
|
|
public string StudentFilePath = "";//If admin, this is used to store the path of the directory where student files are stored.
|
|
|
|
string _UserName="";
|
|
/// <summary>
|
|
/// The username of the person. Will be used as a filename. Cannot be changed once it is set
|
|
/// </summary>
|
|
public string UserName { get { return _UserName; } }
|
|
/// <summary>
|
|
/// The filename, without the path, of the file. UserName + ".enbu"
|
|
/// </summary>
|
|
public string FileName { get { return UserName + ".enbu"; } }
|
|
|
|
/// <summary>
|
|
/// The full name of the person. Can have spaces and punctuation. Can change as one wants it changed.
|
|
/// </summary>
|
|
public string FullName = "";
|
|
|
|
public string Password = "";
|
|
|
|
string PasswordHint = "";
|
|
/// <summary>
|
|
/// The AltPassword is mainly used to hold the admin decrypting password. The student account will
|
|
/// use this to encrypt the student password, so the admin can open their file.
|
|
/// </summary>
|
|
public string AltPassword = "";
|
|
/// <summary>
|
|
/// Used to determine if the user we are working with is the admin account.
|
|
/// </summary>
|
|
public bool isAdmin { get; protected set; }
|
|
|
|
public string EncryptionPassword { get { return UserName + Password; } }
|
|
|
|
public List<SchoolworkClass> Projects = new List<SchoolworkClass>();
|
|
|
|
public List<PersonClass> Students = new List<PersonClass>(); //only teachers (admins) will have students.
|
|
|
|
public NBSettings UserSettings = new NBSettings();
|
|
|
|
public bool ChangePassAtFirstLogin = true;
|
|
|
|
private PersonClass()
|
|
{ }
|
|
|
|
public PersonClass(String User, bool MakeAdmin)
|
|
{
|
|
_UserName = User;
|
|
isAdmin = MakeAdmin;
|
|
}
|
|
|
|
public PersonClass(string Filename)
|
|
{
|
|
Load(Filename);
|
|
string FileAndExtension = Path.GetFileName(Filename);
|
|
string JustFile = Path.GetFileNameWithoutExtension(Filename);
|
|
if(UserName != JustFile)
|
|
{
|
|
throw new Exception(string.Format(NB.Translate("PPF_TamperedFile"), FileAndExtension, UserName));
|
|
}
|
|
}
|
|
public PersonClass(XmlNode reader)
|
|
{
|
|
Load(reader);
|
|
}
|
|
/// <summary>
|
|
/// Try to load the specified filename. Return a new person record if it succeeds.
|
|
/// Return null if it fails to load. (bad password, bad file, etc)
|
|
/// </summary>
|
|
/// <param name="Filename">The filename to load</param>
|
|
/// <param name="password">The password to try</param>
|
|
/// <returns></returns>
|
|
public static PersonClass TryLoad(string Filename, string password)
|
|
{
|
|
PersonClass pc = new PersonClass();
|
|
if (pc.Load(Filename, password))
|
|
return pc;
|
|
return null;
|
|
}
|
|
|
|
public void ChangePassword(string NewPassword)
|
|
{
|
|
Password = NewPassword;
|
|
}
|
|
|
|
public void ChangePassword(bool TryOnce=false)
|
|
{
|
|
bool done = false;
|
|
while (!done)
|
|
{
|
|
if (TryOnce) done = true; //Just attempt it once.
|
|
string OldPassword = "";
|
|
if (Password != "")
|
|
{
|
|
OldPassword = NB.TextPromptBox(NB.Translate("PPF_OldPassword"), Properties.Resources.NBIco, true);
|
|
if (OldPassword != Password)
|
|
{
|
|
MessageBox.Show(NB.Translate("PPF_PassMismatch"));
|
|
continue;
|
|
}
|
|
}
|
|
//The passwords match, or there was no initial password.
|
|
string Password1 = NB.TextPromptBox(NB.Translate("PPF_NewPass"), Properties.Resources.NBIco, true);
|
|
if (Password1.Length < 4)
|
|
{
|
|
MessageBox.Show(NB.Translate("PPF_PassTooShort"));
|
|
continue;
|
|
}
|
|
if (Password1 == OldPassword)
|
|
{
|
|
MessageBox.Show(NB.Translate("PPF_PassDidNotChange"));
|
|
continue;
|
|
}
|
|
string Password2 = NB.TextPromptBox(NB.Translate("PPF_VerifyPass"), Properties.Resources.NBIco, true);
|
|
if (Password1 != Password2)
|
|
{
|
|
MessageBox.Show(NB.Translate("PPF_PassValidateMismatch"));
|
|
continue;
|
|
}
|
|
ChangePassword(Password1);
|
|
|
|
if (ChangePassAtFirstLogin) ChangePassAtFirstLogin = false;//It was done. No need to do it again.
|
|
done = true;
|
|
}
|
|
}
|
|
|
|
#region Load and Save
|
|
//Load and save functions
|
|
public bool Load(string filename, string password = "")
|
|
{
|
|
XmlDocument xmlDoc = new XmlDocument();
|
|
if (File.Exists(filename))
|
|
{
|
|
xmlDoc.Load(filename);
|
|
if (TryToDecrypt(xmlDoc, password) != null)
|
|
{
|
|
Load(xmlDoc);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void Load(XmlNode TheNode)
|
|
{
|
|
foreach (XmlNode Individual in TheNode.ChildNodes)
|
|
{
|
|
XmlNodeType myNodetype = Individual.NodeType;
|
|
if (myNodetype == XmlNodeType.Element)
|
|
{
|
|
switch (Individual.Name.ToLower())
|
|
{
|
|
case "edunetworkbuilderuser":
|
|
case "edunetworkbuilder":
|
|
case "user":
|
|
Load(Individual);
|
|
break;
|
|
case "username":
|
|
_UserName = Individual.InnerText;
|
|
break;
|
|
case "fullname":
|
|
FullName = Individual.InnerText;
|
|
break;
|
|
case "passwordhint":
|
|
PasswordHint = Individual.InnerText;
|
|
break;
|
|
case "altpassword":
|
|
AltPassword = Individual.InnerText;
|
|
break;
|
|
case "studentfilepath":
|
|
StudentFilePath = Individual.InnerText;
|
|
break;
|
|
case "isadmin":
|
|
bool isadmin = false;
|
|
bool.TryParse(Individual.InnerText, out isadmin);
|
|
isAdmin = isadmin;
|
|
break;
|
|
case "changepasswordatlogin":
|
|
bool changepw = false;
|
|
bool.TryParse(Individual.InnerText, out changepw);
|
|
ChangePassAtFirstLogin = changepw;
|
|
break;
|
|
case "password":
|
|
Password = Individual.InnerText;
|
|
break;
|
|
case "settings":
|
|
UserSettings = NB.Deserialize<NBSettings>(Individual.InnerText);
|
|
break;
|
|
case "project":
|
|
case "schoolwork":
|
|
SchoolworkClass SWC = new SchoolworkClass(Individual);
|
|
Projects.Add(SWC);
|
|
break;
|
|
case "student":
|
|
PersonClass PC = new PersonClass(Individual);
|
|
Students.Add(PC);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Save(bool doRotation = false)
|
|
{
|
|
//Save to our pre-existing / pre-defined file
|
|
string filename = Path.Combine(filepath, FileName);
|
|
Save(filename, doRotation);
|
|
}
|
|
|
|
public void Save(string filename, bool doRotation = false)
|
|
{
|
|
XmlWriterSettings settings = new XmlWriterSettings();
|
|
settings.Indent = true;
|
|
settings.NewLineOnAttributes = true;
|
|
if (doRotation && File.Exists(filename))
|
|
NB.MoveFileWithRotation(filename); //make a backup of the file
|
|
|
|
//Generate a doc that has a writer attached. All the normal save funcs work with the writer,
|
|
//But, we can encrypt the XmlDocument
|
|
XmlDocument doc = new XmlDocument();
|
|
using (XmlWriter writer = doc.CreateNavigator().AppendChild())
|
|
{
|
|
//XmlWriter writer = XmlWriter.Create(filename, settings);
|
|
|
|
//Now we write the file:
|
|
writer.WriteStartDocument();
|
|
writer.WriteStartElement("EduNetworkBuilderUser");
|
|
writer.WriteComment("This is a user file for EduNetworkBuilder.");
|
|
Save(writer);
|
|
writer.WriteEndElement();
|
|
writer.WriteEndDocument();
|
|
}
|
|
if(TryToEncrypt(doc) != null)
|
|
doc.Save(filename);
|
|
else
|
|
{
|
|
//We should blow up gracefully. Not sure why we failed.
|
|
}
|
|
}
|
|
|
|
|
|
public void Save(XmlWriter writer, bool AsStudent=false)
|
|
{
|
|
//Save the language name
|
|
//save the number of items
|
|
//Save all the items
|
|
string Element = "User";
|
|
if (AsStudent) Element = "Student";
|
|
writer.WriteStartElement(Element);
|
|
writer.WriteElementString("UserName", UserName);
|
|
writer.WriteElementString("FullName", FullName);
|
|
writer.WriteElementString("PasswordHint", PasswordHint);
|
|
if(isAdmin) //only admins have students, so they are the only ones who need to store this path
|
|
writer.WriteElementString("StudentFilePath", StudentFilePath);
|
|
if (AltPassword == "") AltPassword = TrippleDESDocumentEncryption.GenMachinePW(NB.GetRandom());
|
|
writer.WriteElementString("AltPassword", AltPassword);
|
|
writer.WriteElementString("IsAdmin", isAdmin.ToString());
|
|
writer.WriteElementString("ChangePasswordAtLogin", ChangePassAtFirstLogin.ToString());
|
|
string settingsstring = NB.SerializeObject<NBSettings>(UserSettings);
|
|
writer.WriteElementString("Settings", settingsstring);
|
|
|
|
writer.WriteElementString("Password", Password);
|
|
foreach (PersonClass PC in Students)
|
|
PC.Save(writer, true); //Save as a student entry
|
|
//Save all the devices
|
|
foreach (SchoolworkClass One in Projects)
|
|
{
|
|
One.Save(writer);
|
|
}
|
|
writer.WriteEndElement();
|
|
}
|
|
|
|
private XmlDocument TryToEncrypt(XmlDocument What)
|
|
{
|
|
string UserPassword = UserName + Password;
|
|
if (UserPassword == "") return null; //This should never happen
|
|
string salt = TrippleDESDocumentEncryption.GenSalt(NB.GetRandom());
|
|
|
|
TripleDES tDESkey = TrippleDESDocumentEncryption.GenKey(UserPassword, salt);
|
|
TrippleDESDocumentEncryption xmlTDES = new TrippleDESDocumentEncryption(What, tDESkey);
|
|
|
|
try
|
|
{
|
|
// Encrypt the "user" element.
|
|
xmlTDES.Encrypt("User");
|
|
//make the entries for the key
|
|
XmlNode tNode = xmlTDES.Doc.CreateElement("EncryptedKey");
|
|
tNode.InnerText = UserPassword;
|
|
XmlElement inputElement = xmlTDES.Doc.GetElementsByTagName("EncryptedData")[0] as XmlElement;
|
|
xmlTDES.Doc.DocumentElement.InsertAfter(tNode, inputElement);
|
|
|
|
//add the salt
|
|
tNode = xmlTDES.Doc.CreateElement("Salt");
|
|
tNode.InnerText = salt;
|
|
xmlTDES.Doc.DocumentElement.InsertAfter(tNode, inputElement);
|
|
|
|
//encrypt the user key with the admin key
|
|
xmlTDES.SetKey(AltPassword, salt);
|
|
xmlTDES.Encrypt("EncryptedKey");
|
|
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine(e.Message);
|
|
return null;
|
|
}
|
|
return xmlTDES.Doc;
|
|
}
|
|
|
|
private XmlDocument TryToDecrypt(XmlDocument What, string PassToTry)
|
|
{
|
|
bool first_failed = false;
|
|
XmlElement inputElement = What.GetElementsByTagName("Salt")[0] as XmlElement;
|
|
if (inputElement == null) return What; //No salt means it was never encrypted. Load as normal
|
|
string salt = inputElement.InnerText;
|
|
// Create a new TripleDES key.
|
|
TripleDES tDESkey = TrippleDESDocumentEncryption.GenKey(PassToTry, salt);
|
|
TrippleDESDocumentEncryption xmlTDES = new TrippleDESDocumentEncryption(What, tDESkey);
|
|
|
|
//First, try to decrypt it using the user password.
|
|
try
|
|
{
|
|
xmlTDES.Decrypt("User");
|
|
}
|
|
catch (LoginException le)
|
|
{
|
|
//we ignore this. Just try it again.
|
|
first_failed = true;
|
|
}
|
|
catch(Exception e) //This is bad. Blow up and exit the function
|
|
{
|
|
MessageBox.Show(e.ToString());
|
|
return null;
|
|
}
|
|
|
|
if (first_failed)
|
|
{ //try a second one, decrypting the alt key and then using that. The admin does this.
|
|
// Create a new instance of the TrippleDESDocumentEncryption object
|
|
// defined in this sample.
|
|
try
|
|
{
|
|
xmlTDES.Decrypt("EncryptedKey");
|
|
|
|
inputElement = xmlTDES.Doc.GetElementsByTagName("EncryptedKey")[0] as XmlElement;
|
|
|
|
string userpw = inputElement.InnerText;
|
|
xmlTDES.SetKey(userpw, salt);
|
|
|
|
xmlTDES.Decrypt("User");
|
|
}
|
|
catch (LoginException le)
|
|
{
|
|
//Neither password worked. Exit out so we can prompt for an appropriate password
|
|
return null;
|
|
}
|
|
catch (Exception e) //This is bad. Blow up and exit the function
|
|
{
|
|
MessageBox.Show(e.ToString());
|
|
return null;
|
|
}
|
|
}
|
|
return xmlTDES.Doc;
|
|
}
|
|
#endregion
|
|
|
|
public bool AddHomework(SchoolworkClass ToAdd)
|
|
{
|
|
//Check to see if we already exist
|
|
foreach(SchoolworkClass one in Projects)
|
|
{
|
|
if (one.ThisID == ToAdd.ThisID) return false;
|
|
}
|
|
Projects.Add(ToAdd);
|
|
if (ToAdd.ThisID >= UserSettings.NextID) UserSettings.NextID = (uint)(ToAdd.ThisID + 1);
|
|
return true;
|
|
}
|
|
|
|
public bool HasHomework(SchoolworkClass ToCheck, bool compare_ID)
|
|
{
|
|
//Check to see if we already exist
|
|
foreach (SchoolworkClass one in Projects)
|
|
{
|
|
if (compare_ID && one.ThisID == ToCheck.ThisID)
|
|
return true;
|
|
else if (!compare_ID && one.Name.ToLower() == ToCheck.Name.ToLower())
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool RegisterNewlySubmittedHW(SchoolworkClass ToCheck)
|
|
{
|
|
//Check to see if we already exist
|
|
foreach (SchoolworkClass one in Projects)
|
|
{
|
|
if (one.ThisID == ToCheck.ThisID)
|
|
{
|
|
if (one.SaveDate == ToCheck.SaveDate)
|
|
return false; //They were the same
|
|
}
|
|
}
|
|
//If we get here, we do not yet have it. Add it to the user.
|
|
Projects.Add(ToCheck.Clone());
|
|
return true;
|
|
}
|
|
|
|
public void LoadHomeworkFile(string HomeworkFile)
|
|
{
|
|
if (!File.Exists(HomeworkFile)) return; //The file does not exist
|
|
if (! (Path.GetExtension(HomeworkFile).ToLower() == ".enbh")) return; //It is not a homework file
|
|
List<SchoolworkClass> WhatWeRead = SchoolworkClass.LoadMultiple(HomeworkFile);
|
|
if(WhatWeRead.Count > 0) //We have something to import
|
|
{
|
|
bool IsOK = true;
|
|
//Verify that all the homeworks are OK to load
|
|
foreach(SchoolworkClass one in WhatWeRead)
|
|
{
|
|
//if one is already submitted, reject it
|
|
if(one.IsSumbitted || one.IsGraded)
|
|
{
|
|
IsOK = false;
|
|
}
|
|
}
|
|
//Load them
|
|
if(IsOK)
|
|
{
|
|
int totalHW =0;
|
|
int Skipped = 0;
|
|
int imported = 0;
|
|
if (isAdmin)
|
|
{
|
|
Dictionary<string, bool> InitialList = new Dictionary<string, bool>();
|
|
//use a check-box list
|
|
foreach (SchoolworkClass one in WhatWeRead)
|
|
{
|
|
//Use due date and name + already exists (name / ID)
|
|
string Info = one.DueDate.ToShortDateString();
|
|
Info += "\t" + one.Name;
|
|
if (HasHomework(one, true)) Info += " * " + string.Format(NB.Translate("PC_HWHasID"),one.ThisID);
|
|
if (HasHomework(one, false)) Info += " ** " + string.Format(NB.Translate("PC_HWHasName"));
|
|
InitialList.Add(Info, false);
|
|
}
|
|
Dictionary<string, bool> ResponseList = NB.CheckPromptBox(InitialList, "Import", Properties.Resources.NBIco);
|
|
|
|
if (ResponseList == null) return; //They canceled out.
|
|
|
|
int index = 0;
|
|
foreach(string One in ResponseList.Keys)
|
|
{
|
|
totalHW++;
|
|
if (ResponseList[One])
|
|
{ //We are supposed to import it.
|
|
if (HasHomework(WhatWeRead[index], true))
|
|
{ //We already have this ID. Get a new ID
|
|
WhatWeRead[index].ChangeID(this); //Pass in this user, whoever we are
|
|
}
|
|
//Now we can add it without issue.
|
|
AddHomework(WhatWeRead[index]);
|
|
imported++;
|
|
}
|
|
else
|
|
Skipped++;
|
|
index++;
|
|
}
|
|
//they check if they want to import
|
|
//We never overwrite, we make a new one, with new ID
|
|
}
|
|
else
|
|
{
|
|
foreach (SchoolworkClass one in WhatWeRead)
|
|
{
|
|
totalHW++;
|
|
|
|
if (AddHomework(one))
|
|
{
|
|
imported++;
|
|
}
|
|
else
|
|
{
|
|
Skipped++;
|
|
}
|
|
}
|
|
}
|
|
MessageBox.Show(string.Format(NB.Translate("PC_HWFileImportStats"),"\n\t" + totalHW, "\n\t" + imported, "\n\t" + Skipped));
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show(NB.Translate("PC_AlreadySubmittedOrGraded"));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Organize the projects into a nice project tree.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public TreeNode WorkTree(TreeNode theTop=null, bool ForTeacher = false)
|
|
{
|
|
//Sort by due date, and within the due dates, sort by save date
|
|
Projects.Sort((q, p) => p.Compare(q));
|
|
|
|
List<SchoolworkClass> DrawFrom = new List<SchoolworkClass>();
|
|
List<SchoolworkClass> MasterList = new List<SchoolworkClass>();
|
|
bool SomethingWasBolded = false; //Set this to true if we make something bold
|
|
|
|
DrawFrom.AddRange(Projects);
|
|
for (int i = DrawFrom.Count - 1; i >= 0; i--)
|
|
{
|
|
if (DrawFrom[i].isMaster)
|
|
{
|
|
MasterList.Add(DrawFrom[i]);
|
|
DrawFrom.RemoveAt(i);
|
|
}
|
|
}
|
|
//Now, all the masters are in Master, and submitted projects are in DrawFrom.
|
|
|
|
TreeNode Node;
|
|
TreeNode Top;
|
|
TreeNode Master;
|
|
//We have a class tree
|
|
if (theTop == null)
|
|
{
|
|
Top = new TreeNode(NB.Translate("PPF_Class"));
|
|
Top.Tag = "Class"; //Do not translate this
|
|
}
|
|
else
|
|
{
|
|
Top = theTop;
|
|
}
|
|
Font tFont = NB.GetFont();
|
|
|
|
foreach (SchoolworkClass MasterSW in MasterList)
|
|
{
|
|
int count = 0;
|
|
int ungraded = 0;
|
|
Master = new TreeNode(MasterSW.Name);
|
|
Master.Tag = MasterSW;
|
|
|
|
for (int i = DrawFrom.Count -1; i>=0; i--)
|
|
{
|
|
if(DrawFrom[i].ThisID == MasterSW.ThisID)
|
|
{
|
|
Node = new TreeNode(DrawFrom[i].Name);
|
|
Node.Tag = DrawFrom[i];
|
|
string tooltip = FullName + "\n";
|
|
tooltip += DrawFrom[i].Name + "\n";
|
|
tooltip += DrawFrom[i].Description + "\n";
|
|
if(DrawFrom[i].IsSumbitted)
|
|
tooltip += "Submitted: " + DrawFrom[i].SaveDate.ToShortDateString() + "\n";
|
|
if(DrawFrom[i].theProject != null)
|
|
{
|
|
List<string> tMessages = DrawFrom[i].theProject.GetMessageStrings();
|
|
foreach(string one in tMessages)
|
|
{
|
|
tooltip += one + "\n";
|
|
}
|
|
}
|
|
Node.ToolTipText = tooltip;
|
|
Master.Nodes.Add(Node);
|
|
if (ForTeacher && !DrawFrom[i].IsGraded) //Bold ungraded homework
|
|
{
|
|
Node.NodeFont = new Font(tFont.FontFamily, tFont.Size, FontStyle.Bold);
|
|
SomethingWasBolded = true;
|
|
ungraded++;
|
|
}
|
|
count++; //How many submitted versions are there
|
|
}
|
|
}
|
|
if(!ForTeacher && count ==0) //bold homework that has not yet been submitted
|
|
{
|
|
Master.NodeFont = new Font(tFont.FontFamily, tFont.Size, FontStyle.Bold);
|
|
SomethingWasBolded = true;
|
|
} else if(ForTeacher && ungraded > 0) //If we have ungraded submissions
|
|
{
|
|
Master.NodeFont = new Font(tFont.FontFamily, tFont.Size, FontStyle.Bold);
|
|
SomethingWasBolded = true;
|
|
}
|
|
Top.Nodes.Add(Master);
|
|
}
|
|
|
|
if(ForTeacher && SomethingWasBolded)
|
|
Top.NodeFont = new Font(tFont.FontFamily, tFont.Size, FontStyle.Bold);
|
|
return Top;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return the student with the specified UserName
|
|
/// </summary>
|
|
/// <param name="UserName">The user name to find</param>
|
|
/// <returns>The specified person, or null if no such person exists.</returns>
|
|
public PersonClass StudentWithTheUserName(string UserName)
|
|
{
|
|
if (!isAdmin) return null; //Students do not store other student records
|
|
foreach(PersonClass PC in Students)
|
|
{
|
|
if (PC.UserName == UserName) return PC;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Import the settings from a student record
|
|
/// </summary>
|
|
/// <param name="ImportedStudent">the student we are importing from</param>
|
|
/// <returns>The count of homeworks we added. -1 if there is an error</returns>
|
|
public int TeacherImportStudentHomework(PersonClass ImportedStudent)
|
|
{
|
|
if (!isAdmin) return -1;
|
|
PersonClass StoredStudent = StudentWithTheUserName(ImportedStudent.UserName);
|
|
if (StoredStudent == null) return -1;
|
|
|
|
int NumSubmitted = 0;
|
|
|
|
//Retrieve all the stored settings, in case we need to re-write their file
|
|
StoredStudent.UserSettings = ImportedStudent.UserSettings;
|
|
|
|
//Pull out their password, in case we want to retrieve it. (sigh)
|
|
StoredStudent.Password = ImportedStudent.Password;
|
|
|
|
// loop through all networks
|
|
foreach (SchoolworkClass SWC in ImportedStudent.Projects)
|
|
{
|
|
// Find any that are submitted, which are not in the admin file
|
|
if (StoredStudent.RegisterNewlySubmittedHW(SWC))
|
|
{
|
|
// copy them into the admin file
|
|
if(SWC.IsSumbitted) //Only report submitted homeworks back.
|
|
NumSubmitted++;
|
|
}
|
|
}
|
|
return NumSubmitted;
|
|
}
|
|
|
|
}
|
|
}
|