mirror of git3://git3.w3q/git3-contract
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
5.2 KiB
Solidity
167 lines
5.2 KiB
Solidity
pragma solidity ^0.8.0;
|
|
|
|
// import "hardhat/console.sol";
|
|
// import "@openzeppelin/contracts/access/Ownable.sol";
|
|
|
|
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
|
|
import "@openzeppelin/contracts-upgradeable/access/AccessControlEnumerableUpgradeable.sol";
|
|
import "./EnumerableSet.sol";
|
|
import "./Repositorylib.sol";
|
|
import "./database/database.sol";
|
|
contract Hub is AccessControlEnumerableUpgradeable{
|
|
|
|
using EnumerableSet for EnumerableSet.AddressSet;
|
|
using RepositoryLib for RepositoryLib.BranchInfo;
|
|
|
|
// Hub Info
|
|
bytes32 public constant CREATOR = bytes32(uint256(0));
|
|
bytes32 public constant MANAGER = bytes32(uint256(1));
|
|
bytes32 public constant CONTRIBUTOR = bytes32(uint256(2));
|
|
bytes32[] public RoleList = [CREATOR,MANAGER,CONTRIBUTOR];
|
|
bool public permissionless;
|
|
|
|
// Repository Info
|
|
struct RepositoryInfo{
|
|
uint256 repoNameIndex;
|
|
address owner;
|
|
bool exist;
|
|
EnumerableSet.AddressSet repoContributors;
|
|
RepositoryLib.BranchInfo branchs;
|
|
}
|
|
|
|
mapping(bytes=>RepositoryInfo) nameToRepository;
|
|
bytes[] public repoNames;
|
|
|
|
// DataBase Info
|
|
database public db;
|
|
|
|
|
|
// ===== hub operator functions======
|
|
function openPermissonlessJoin(bool open) public {
|
|
require(hasRole(CREATOR, _msgSender()));
|
|
permissionless = open;
|
|
}
|
|
|
|
function memberShip() public view returns(bool){
|
|
if (hasRole(CREATOR, _msgSender())){
|
|
return true;
|
|
}else if (hasRole(MANAGER, _msgSender())){
|
|
return true;
|
|
}else if (hasRole(CONTRIBUTOR, _msgSender())){
|
|
return true;
|
|
}else{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//createRepository can be invoked by anyone within Hub
|
|
function createRepository(bytes memory repoName) public{
|
|
require(memberShip());
|
|
require(
|
|
repoName.length > 0 && repoName.length <= 100,
|
|
"RepoName length must be 1-100"
|
|
);
|
|
for (uint i; i < repoName.length; i++) {
|
|
bytes1 char = repoName[i];
|
|
require(
|
|
(char >= 0x61 && char <= 0x7A) || //a-z
|
|
(char >= 0x41 && char <= 0x5A) || //A-Z
|
|
(char >= 0x30 && char <= 0x39) || //0-9
|
|
(char == 0x2D || char == 0x2E || char == 0x5F), //-._
|
|
"RepoName must be alphanumeric or -._"
|
|
);
|
|
}
|
|
|
|
RepositoryInfo storage repo = nameToRepository[repoName];
|
|
require(
|
|
repo.exist == false ,
|
|
"RepoName already exist"
|
|
);
|
|
|
|
repo.repoNameIndex = repoNames.length;
|
|
repo.owner = _msgSender();
|
|
repo.exist = true;
|
|
repoNames.push(repoName);
|
|
}
|
|
|
|
function deleteRepository(bytes memory repoName) public returns(address){
|
|
require(hasRole(CREATOR, _msgSender()) || hasRole(MANAGER, _msgSender()));
|
|
require(nameToRepository[repoName].exist==true,"repoName do not exist");
|
|
delete(nameToRepository[repoName]);
|
|
}
|
|
|
|
function addMember( bytes32 senderRole , bytes32 role,address member) public{
|
|
require(hasRole(senderRole, _msgSender()));
|
|
require(senderRole>role);
|
|
grantRole(role, member);
|
|
}
|
|
|
|
|
|
function deleteMember(bytes32 senderRole ,bytes32 role,address member) public{
|
|
require(hasRole(senderRole, _msgSender()));
|
|
require(senderRole>role);
|
|
revokeRole(role, member);
|
|
}
|
|
|
|
// permissionlessJoin can be invoked by everyone who want to join this hub
|
|
function permissionlessJoin() public{
|
|
require(permissionless,"permissionless join no open");
|
|
grantRole(CONTRIBUTOR, _msgSender());
|
|
}
|
|
|
|
// ===== repository operator functions======
|
|
|
|
function isRepoContributor(bytes memory repoName , address member) internal view returns(bool){
|
|
RepositoryInfo storage repo = nameToRepository[repoName];
|
|
if (repo.owner == member) return true;
|
|
if (repo.repoContributors.contains(member)) {
|
|
return true;
|
|
}else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function listRepoBranchs( bytes memory repoName)external view {
|
|
nameToRepository[repoName].branchs.listBranchs();
|
|
}
|
|
|
|
function updateRepoBranch(
|
|
bytes memory repoName,
|
|
bytes memory branchPath,
|
|
bytes20 refHash
|
|
)external{
|
|
require(isRepoContributor(repoName, _msgSender()));
|
|
nameToRepository[repoName].branchs.updateBranch(repoName,branchPath,refHash);
|
|
}
|
|
|
|
function removeRepoBranch(
|
|
bytes memory repoName,
|
|
bytes memory branchPath
|
|
) external{
|
|
require(isRepoContributor(repoName, _msgSender()));
|
|
nameToRepository[repoName].branchs.removeBranch(repoName,branchPath);
|
|
}
|
|
|
|
// ===== database operator functions======
|
|
function newDataBase() external onlyRole(CREATOR) {
|
|
|
|
}
|
|
|
|
function download(
|
|
bytes memory repoName,
|
|
bytes memory path
|
|
) external view returns (bytes memory, bool) {
|
|
// call flat directory(FD)
|
|
return db.download(repoName, path);
|
|
}
|
|
|
|
function upload(
|
|
bytes memory repoName,
|
|
bytes memory path,
|
|
bytes calldata data
|
|
) external payable {
|
|
return db.upload(repoName, path,data);
|
|
}
|
|
|
|
}
|