From 86a8b6cf3932dececfd1d6f9ff0e5679f45e97da Mon Sep 17 00:00:00 2001 From: salim imuzai Date: Sun, 28 Jul 2024 21:16:19 +0100 Subject: [PATCH] feat - implement update student mapping and array --- .vscode/settings.json | 2 +- contracts/StudentRegistry.sol | 135 +++++++++++++----- .../modifiers/AccessControlModifiers.sol | 37 +++++ contracts/modifiers/InputValidation.sol | 39 +++++ 4 files changed, 175 insertions(+), 38 deletions(-) create mode 100644 contracts/modifiers/AccessControlModifiers.sol create mode 100644 contracts/modifiers/InputValidation.sol diff --git a/.vscode/settings.json b/.vscode/settings.json index bc1c7197..19035be5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "solidity.compileUsingRemoteVersion": "v0.8.14+commit.80d49f37" + "solidity.compileUsingRemoteVersion": "v0.8.24+commit.e11b9ed9" } \ No newline at end of file diff --git a/contracts/StudentRegistry.sol b/contracts/StudentRegistry.sol index 4f5bb554..e35ded7b 100644 --- a/contracts/StudentRegistry.sol +++ b/contracts/StudentRegistry.sol @@ -1,8 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; +import './modifiers/AccessControlModifiers.sol'; +import './modifiers/InputValidation.sol'; -contract StudentRegistry { - //custom data type +/// @title Student Registry Contract +/// @notice This contract allows the management of students' information +/// @dev This contract uses access control and input validation modifiers +contract StudentRegistry is AccessControlModifiers, InputValidation { + + + /// @dev Custom data type representing a student struct Student { address studentAddr; string name; @@ -10,36 +17,35 @@ contract StudentRegistry { uint8 age; } - address public owner; + /// @dev Dynamic array of students + Student[] private students; - constructor() { - owner = msg.sender; - } + /// @dev Mapping from address to Student struct + mapping(address => Student) private studentsMapping; - //dynamic array of students - Student[] private students; + /// @dev Event emitted when a new student is added + /// @param studentsMapping[_studentAddr] or students[_studentId - 1] The student that was added + event addNewStudentEvent(Student students, Student studentsMapping); - mapping(address => Student) public studentsMapping; + /// @dev Event emitted when a student is deleted from the array + /// @param students[_studentId - 1] The student that was deleted + event deleteStudentEvent(Student students); - modifier onlyOwner () { - require( owner == msg.sender, "You fraud!!!"); - _; - } + /// @dev Event emitted when a student is deleted from the mapping + /// @param studentsMapping[_studentAddr] The student that was deleted + event deleteStudentFromMappingEvent(Student studentsMapping); - modifier isNotAddressZero () { - require(msg.sender != address(0), "Invalid Address"); - _; - } + /// @notice Adds a new student to the registry + /// @dev Only the owner can add a new student + /// @param _studentAddr The address of the student + /// @param _name The name of the student + /// @param _age The age of the student function addStudent( address _studentAddr, string memory _name, uint8 _age - ) public onlyOwner isNotAddressZero { - - require( bytes(_name).length > 0, "Name cannot be blank"); - require( _age >= 18, "This student is under age"); - + ) public onlyOwner validateStudentAge(_age) validateStudentName(_name) validateStudentAddress(_studentAddr) { uint256 _studentId = students.length + 1; Student memory student = Student({ studentAddr: _studentAddr, @@ -49,41 +55,96 @@ contract StudentRegistry { }); students.push(student); - // add student to studentsMapping + //@dev add student to studentsMapping studentsMapping[_studentAddr] = student; + emit addNewStudentEvent(students[_studentId - 1], studentsMapping[_studentAddr]); } - function getStudent(uint8 _studentId) public isNotAddressZero view returns (Student memory) { + /// @notice Gets a student by their ID + /// @param _studentId The ID of the student + /// @return The student with the specified ID + function getStudent(uint8 _studentId) public validateStudentId(_studentId) view returns (Student memory) { + require(_studentId < students.length, "student Id does not exist"); return students[_studentId - 1]; } - - + /// @notice Gets a student by their address from the mapping + /// @param _studentAddr The address of the student + /// @return The student with the specified address function getStudentFromMapping(address _studentAddr) - public - isNotAddressZero + public validateStudentAddress(_studentAddr) view returns (Student memory) { return studentsMapping[_studentAddr]; } + /// @notice Deletes a student by their ID from the array + /// @dev Only the owner can delete a student + /// @param _studentId The ID of the student to delete + function deleteStudent(uint8 _studentId) public onlyOwner { + require(_studentId < students.length, "student Id does not exist"); + for (uint256 i = 0; i < students.length; i++) { + if (students[i].studentId == _studentId) { + //@dev Maintaining Order in the array + students[i] = students[i + 1]; + ///@dev Not Maintaining Order in the array + // students[i] = students[students.length - 1]; + // students.pop(); + // emit deleteStudentEvent(students[_studentId - 1]); + // break; + } + } + students.pop(); + emit deleteStudentEvent(students[_studentId - 1]); + } + /// @notice Deletes a student by their address from the mapping + /// @dev Only the owner can delete a student + /// @param _studentAddr The address of the student to delete + function deleteStudentFromMapping(address _studentAddr) public onlyOwner { + require(studentsMapping[_studentAddr].studentAddr != address(0), "Student does not exist"); + delete studentsMapping[_studentAddr]; - function deleteStudent(address _studentAddr) public onlyOwner isNotAddressZero{ + } + /// @notice Updates a student in the mapping + /// @dev Only the owner can update a student + /// @param _studentAddr The address of the student to update + /// @param _name The new name of the student + /// @param _age The new age of the student + function updateStudentFromMapping( + address _studentAddr, + string memory _name, + uint8 _age + ) public onlyOwner { require(studentsMapping[_studentAddr].studentAddr != address(0), "Student does not exist"); - // delete studentsMapping[_studentAddr]; + Student storage student = studentsMapping[_studentAddr]; + student.name = _name; + student.age = _age; + } - Student memory student = Student({ - studentAddr: address(0), - name: "", - age: 0, - studentId: 0 - }); + /// @notice Updates a student in the array + /// @dev Only the owner can update a student + /// @param _studentId The ID of the student to update + /// @param _studentAddr The new address of the student + /// @param _name The new name of the student + /// @param _age The new age of the student + function updateStudent( + uint8 _studentId, + address _studentAddr, + string memory _name, + uint8 _age + ) public onlyOwner validateStudentId(_studentId) { + require(_studentId <= students.length, "student Id does not exist"); - studentsMapping[_studentAddr] = student; + Student storage student = students[_studentId - 1]; + student.studentAddr = _studentAddr; + student.name = _name; + student.age = _age; + //@dev Also update the student in studentsMapping + studentsMapping[_studentAddr] = student; } } diff --git a/contracts/modifiers/AccessControlModifiers.sol b/contracts/modifiers/AccessControlModifiers.sol new file mode 100644 index 00000000..cc72ea49 --- /dev/null +++ b/contracts/modifiers/AccessControlModifiers.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +/// @title Access Control Modifiers Contract +/// @notice This contract contains access control modifiers for ownership and authorization +contract AccessControlModifiers { + address private owner; + + /// @notice Constructor sets the contract deployer as the owner + constructor() { + owner = msg.sender; + } + + /// @notice Modifier to allow only the owner to execute the function + /// @dev Reverts if the caller is not the contract owner + modifier onlyOwner() { + require(msg.sender == owner, "Not the contract owner"); + _; + } + + /// @notice Modifier to allow only authorized addresses to execute the function + /// @dev Reverts if the address is not authorized + /// @param _address The address to check for authorization + modifier onlyAuthorized(address _address) { + require(isAuthorized(_address), "Not authorized"); + _; + } + + /// @notice Checks if an address is authorized + /// @dev This is a placeholder function for custom authorization logic + /// @param _address The address to check for authorization + /// @return bool True if the address is authorized, false otherwise + function isAuthorized(address _address) internal view returns (bool) { + //@dev Custom authorization logic + return _address == owner; + } +} \ No newline at end of file diff --git a/contracts/modifiers/InputValidation.sol b/contracts/modifiers/InputValidation.sol new file mode 100644 index 00000000..b1c166ed --- /dev/null +++ b/contracts/modifiers/InputValidation.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +/// @title Input Validation Contract +/// @notice This contract contains modifiers to validate inputs for student registration +contract InputValidation { + + /// @notice Modifier to validate the age of the student + /// @dev Ensures that the student is at least 18 years old + /// @param _age The age of the student + modifier validateStudentAge(uint256 _age) { + require( _age >= 18, "This student is under age"); + _; + } + + /// @notice Modifier to validate the name of the student + /// @dev Ensures that the name is not blank + /// @param _name The name of the student + modifier validateStudentName(string memory _name) { + require( bytes(_name).length > 0, "Name cannot be blank"); + _; + } + + /// @notice Modifier to validate the ID of the student + /// @dev Ensures that the student ID is greater than zero + /// @param _studentId The ID of the student + modifier validateStudentId(uint8 _studentId) { + require(_studentId > 0, "Invalid Student ID"); + _; + } + + /// @notice Modifier to validate the address of the student + /// @dev Ensures that the address is not the zero address + /// @param _studentAddr The address of the student + modifier validateStudentAddress(address _studentAddr) { + require( _studentAddr != address(0), "Invalid Address"); + _; + } +} \ No newline at end of file