VeuReu commited on
Commit
3d89a7c
·
verified ·
1 Parent(s): 92b0172

Upload 18 files

Browse files
app.py CHANGED
@@ -131,6 +131,11 @@ class VideoUploadNotification(BaseModel):
131
  video_name: str
132
  sha1sum: str
133
 
 
 
 
 
 
134
  # --- AUTENTICACIÓN (SIMULADA) ---
135
  def validate_google_token(token: str) -> Optional[Dict[str, Any]]:
136
  """
@@ -614,6 +619,51 @@ def send_video_upload_sms(notification: VideoUploadNotification):
614
  logger.error(f"[VIDEO SMS] Error inesperat enviant SMS al validor: {e}")
615
  raise HTTPException(status_code=500, detail="Error inesperat enviant SMS al validor")
616
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
617
  @app.post("/api/compliance/record-decision")
618
  def record_decision(decision: ValidatorDecision):
619
  """Registra decisión de validador"""
 
131
  video_name: str
132
  sha1sum: str
133
 
134
+
135
+ class LoginSMSRequest(BaseModel):
136
+ phone: str
137
+ code: str
138
+
139
  # --- AUTENTICACIÓN (SIMULADA) ---
140
  def validate_google_token(token: str) -> Optional[Dict[str, Any]]:
141
  """
 
619
  logger.error(f"[VIDEO SMS] Error inesperat enviant SMS al validor: {e}")
620
  raise HTTPException(status_code=500, detail="Error inesperat enviant SMS al validor")
621
 
622
+
623
+ @app.post("/api/notifications/login-sms")
624
+ def send_login_sms(req: LoginSMSRequest):
625
+ """Envia un SMS de verificació de mòbil per al login des de demo.
626
+
627
+ Utilitza el webhook de Zapier (ZAPIER_WEBHOOK_CATCH) definit en aquest space.
628
+ El missatge no inclou el codi en pantalla; el codi s'envia només per SMS.
629
+ """
630
+
631
+ zapier_url = os.getenv("ZAPIER_WEBHOOK_CATCH")
632
+ if not zapier_url:
633
+ logger.error("[LOGIN SMS] ZAPIER_WEBHOOK_CATCH no definit")
634
+ raise HTTPException(status_code=500, detail="ZAPIER webhook not configured")
635
+
636
+ normalized_phone = req.phone.strip().replace(" ", "")
637
+ if not normalized_phone.startswith("+"):
638
+ # Assumir prefix per defecte si no ve amb codi de país
639
+ normalized_phone = "+34" + normalized_phone
640
+
641
+ message = "El teu codi secret de validació és: ****" # No exposem el codi en text o logs
642
+
643
+ try:
644
+ import requests
645
+
646
+ payload = {
647
+ "phone": normalized_phone,
648
+ "message": message,
649
+ "code": req.code,
650
+ }
651
+ resp = requests.post(zapier_url, json=payload, timeout=10)
652
+ if not resp.ok:
653
+ logger.error(
654
+ f"[LOGIN SMS] Error HTTP enviant SMS de login: {resp.status_code} {resp.text}"
655
+ )
656
+ raise HTTPException(status_code=500, detail="Error enviant SMS de login")
657
+
658
+ logger.info(f"[LOGIN SMS] SMS de verificació enviat a {normalized_phone}")
659
+ return {"success": True}
660
+
661
+ except HTTPException:
662
+ raise
663
+ except Exception as e:
664
+ logger.error(f"[LOGIN SMS] Error inesperat enviant SMS de login: {e}")
665
+ raise HTTPException(status_code=500, detail="Error inesperat enviant SMS de login")
666
+
667
  @app.post("/api/compliance/record-decision")
668
  def record_decision(decision: ValidatorDecision):
669
  """Registra decisión de validador"""
polygon/README.txt ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ REMIX DEFAULT WORKSPACE
2
+
3
+ Remix default workspace is present when:
4
+ i. Remix loads for the very first time
5
+ ii. A new workspace is created with 'Default' template
6
+ iii. There are no files existing in the File Explorer
7
+
8
+ This workspace contains 3 directories:
9
+
10
+ 1. 'contracts': Holds three contracts with increasing levels of complexity.
11
+ 2. 'scripts': Contains four typescript files to deploy a contract. It is explained below.
12
+ 3. 'tests': Contains one Solidity test file for 'Ballot' contract & one JS test file for 'Storage' contract.
13
+
14
+ SCRIPTS
15
+
16
+ The 'scripts' folder has four typescript files which help to deploy the 'Storage' contract using 'web3.js' and 'ethers.js' libraries.
17
+
18
+ For the deployment of any other contract, just update the contract name from 'Storage' to the desired contract and provide constructor arguments accordingly
19
+ in the file `deploy_with_ethers.ts` or `deploy_with_web3.ts`
20
+
21
+ In the 'tests' folder there is a script containing Mocha-Chai unit tests for 'Storage' contract.
22
+
23
+ To run a script, right click on file name in the file explorer and click 'Run'. Remember, Solidity file must already be compiled.
24
+ Output from script will appear in remix terminal.
25
+
26
+ Please note, require/import is supported in a limited manner for Remix supported modules.
27
+ For now, modules supported by Remix are ethers, web3, swarmgw, chai, multihashes, remix and hardhat only for hardhat.ethers object/plugin.
28
+ For unsupported modules, an error like this will be thrown: '<module_name> module require is not supported by Remix IDE' will be shown.
polygon/contracts/1_Storage.sol ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // SPDX-License-Identifier: GPL-3.0
2
+
3
+ pragma solidity >=0.8.2 <0.9.0;
4
+
5
+ /**
6
+ * @title Storage
7
+ * @dev Store & retrieve value in a variable
8
+ * @custom:dev-run-script ./scripts/deploy_with_ethers.ts
9
+ */
10
+ contract Storage {
11
+
12
+ uint256 number;
13
+
14
+ /**
15
+ * @dev Store value in variable
16
+ * @param num value to store
17
+ */
18
+ function store(uint256 num) public {
19
+ number = num;
20
+ }
21
+
22
+ /**
23
+ * @dev Return value
24
+ * @return value of 'number'
25
+ */
26
+ function retrieve() public view returns (uint256){
27
+ return number;
28
+ }
29
+ }
polygon/contracts/2_Owner.sol ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // SPDX-License-Identifier: GPL-3.0
2
+
3
+ pragma solidity >=0.7.0 <0.9.0;
4
+
5
+ import "hardhat/console.sol";
6
+
7
+ /**
8
+ * @title Owner
9
+ * @dev Set & change owner
10
+ */
11
+ contract Owner {
12
+
13
+ address private owner;
14
+
15
+ // event for EVM logging
16
+ event OwnerSet(address indexed oldOwner, address indexed newOwner);
17
+
18
+ // modifier to check if caller is owner
19
+ modifier isOwner() {
20
+ // If the first argument of 'require' evaluates to 'false', execution terminates and all
21
+ // changes to the state and to Ether balances are reverted.
22
+ // This used to consume all gas in old EVM versions, but not anymore.
23
+ // It is often a good idea to use 'require' to check if functions are called correctly.
24
+ // As a second argument, you can also provide an explanation about what went wrong.
25
+ require(msg.sender == owner, "Caller is not owner");
26
+ _;
27
+ }
28
+
29
+ /**
30
+ * @dev Set contract deployer as owner
31
+ */
32
+ constructor() {
33
+ console.log("Owner contract deployed by:", msg.sender);
34
+ owner = msg.sender; // 'msg.sender' is sender of current call, contract deployer for a constructor
35
+ emit OwnerSet(address(0), owner);
36
+ }
37
+
38
+ /**
39
+ * @dev Change owner
40
+ * @param newOwner address of new owner
41
+ */
42
+ function changeOwner(address newOwner) public isOwner {
43
+ require(newOwner != address(0), "New owner should not be the zero address");
44
+ emit OwnerSet(owner, newOwner);
45
+ owner = newOwner;
46
+ }
47
+
48
+ /**
49
+ * @dev Return owner address
50
+ * @return address of owner
51
+ */
52
+ function getOwner() external view returns (address) {
53
+ return owner;
54
+ }
55
+ }
polygon/contracts/3_Ballot.sol ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // SPDX-License-Identifier: GPL-3.0
2
+
3
+ pragma solidity >=0.7.0 <0.9.0;
4
+
5
+ /**
6
+ * @title Ballot
7
+ * @dev Implements voting process along with vote delegation
8
+ */
9
+ contract Ballot {
10
+ // This declares a new complex type which will
11
+ // be used for variables later.
12
+ // It will represent a single voter.
13
+ struct Voter {
14
+ uint weight; // weight is accumulated by delegation
15
+ bool voted; // if true, that person already voted
16
+ address delegate; // person delegated to
17
+ uint vote; // index of the voted proposal
18
+ }
19
+
20
+ // This is a type for a single proposal.
21
+ struct Proposal {
22
+ // If you can limit the length to a certain number of bytes,
23
+ // always use one of bytes1 to bytes32 because they are much cheaper
24
+ bytes32 name; // short name (up to 32 bytes)
25
+ uint voteCount; // number of accumulated votes
26
+ }
27
+
28
+ address public chairperson;
29
+
30
+ // This declares a state variable that
31
+ // stores a 'Voter' struct for each possible address.
32
+ mapping(address => Voter) public voters;
33
+
34
+ // A dynamically-sized array of 'Proposal' structs.
35
+ Proposal[] public proposals;
36
+
37
+ /**
38
+ * @dev Create a new ballot to choose one of 'proposalNames'.
39
+ * @param proposalNames names of proposals
40
+ */
41
+ constructor(bytes32[] memory proposalNames) {
42
+ chairperson = msg.sender;
43
+ voters[chairperson].weight = 1;
44
+
45
+ // For each of the provided proposal names,
46
+ // create a new proposal object and add it
47
+ // to the end of the array.
48
+ for (uint i = 0; i < proposalNames.length; i++) {
49
+ // 'Proposal({...})' creates a temporary
50
+ // Proposal object and 'proposals.push(...)'
51
+ // appends it to the end of 'proposals'.
52
+ proposals.push(Proposal({
53
+ name: proposalNames[i],
54
+ voteCount: 0
55
+ }));
56
+ }
57
+ }
58
+
59
+ /**
60
+ * @dev Give 'voter' the right to vote on this ballot. May only be called by 'chairperson'.
61
+ * @param voter address of voter
62
+ */
63
+ function giveRightToVote(address voter) external {
64
+ // If the first argument of `require` evaluates
65
+ // to 'false', execution terminates and all
66
+ // changes to the state and to Ether balances
67
+ // are reverted.
68
+ // This used to consume all gas in old EVM versions, but
69
+ // not anymore.
70
+ // It is often a good idea to use 'require' to check if
71
+ // functions are called correctly.
72
+ // As a second argument, you can also provide an
73
+ // explanation about what went wrong.
74
+ require(
75
+ msg.sender == chairperson,
76
+ "Only chairperson can give right to vote."
77
+ );
78
+ require(
79
+ !voters[voter].voted,
80
+ "The voter already voted."
81
+ );
82
+ require(voters[voter].weight == 0, "Voter already has the right to vote.");
83
+ voters[voter].weight = 1;
84
+ }
85
+
86
+ /**
87
+ * @dev Delegate your vote to the voter 'to'.
88
+ * @param to address to which vote is delegated
89
+ */
90
+ function delegate(address to) external {
91
+ // assigns reference
92
+ Voter storage sender = voters[msg.sender];
93
+ require(sender.weight != 0, "You have no right to vote");
94
+ require(!sender.voted, "You already voted.");
95
+
96
+ require(to != msg.sender, "Self-delegation is disallowed.");
97
+
98
+ // Forward the delegation as long as
99
+ // 'to' also delegated.
100
+ // In general, such loops are very dangerous,
101
+ // because if they run too long, they might
102
+ // need more gas than is available in a block.
103
+ // In this case, the delegation will not be executed,
104
+ // but in other situations, such loops might
105
+ // cause a contract to get "stuck" completely.
106
+ while (voters[to].delegate != address(0)) {
107
+ to = voters[to].delegate;
108
+
109
+ // We found a loop in the delegation, not allowed.
110
+ require(to != msg.sender, "Found loop in delegation.");
111
+ }
112
+
113
+ Voter storage delegate_ = voters[to];
114
+
115
+ // Voters cannot delegate to accounts that cannot vote.
116
+ require(delegate_.weight >= 1);
117
+
118
+ // Since 'sender' is a reference, this
119
+ // modifies 'voters[msg.sender]'.
120
+ sender.voted = true;
121
+ sender.delegate = to;
122
+
123
+ if (delegate_.voted) {
124
+ // If the delegate already voted,
125
+ // directly add to the number of votes
126
+ proposals[delegate_.vote].voteCount += sender.weight;
127
+ } else {
128
+ // If the delegate did not vote yet,
129
+ // add to her weight.
130
+ delegate_.weight += sender.weight;
131
+ }
132
+ }
133
+
134
+ /**
135
+ * @dev Give your vote (including votes delegated to you) to proposal 'proposals[proposal].name'.
136
+ * @param proposal index of proposal in the proposals array
137
+ */
138
+ function vote(uint proposal) external {
139
+ Voter storage sender = voters[msg.sender];
140
+ require(sender.weight != 0, "Has no right to vote");
141
+ require(!sender.voted, "Already voted.");
142
+ sender.voted = true;
143
+ sender.vote = proposal;
144
+
145
+ // If 'proposal' is out of the range of the array,
146
+ // this will throw automatically and revert all
147
+ // changes.
148
+ proposals[proposal].voteCount += sender.weight;
149
+ }
150
+
151
+ /**
152
+ * @dev Computes the winning proposal taking all previous votes into account.
153
+ * @return winningProposal_ index of winning proposal in the proposals array
154
+ */
155
+ function winningProposal() public view
156
+ returns (uint winningProposal_)
157
+ {
158
+ uint winningVoteCount = 0;
159
+ for (uint p = 0; p < proposals.length; p++) {
160
+ if (proposals[p].voteCount > winningVoteCount) {
161
+ winningVoteCount = proposals[p].voteCount;
162
+ winningProposal_ = p;
163
+ }
164
+ }
165
+ }
166
+
167
+ /**
168
+ * @dev Calls winningProposal() function to get the index of the winner contained in the proposals array and then
169
+ * @return winnerName_ the name of the winner
170
+ */
171
+ function winnerName() external view
172
+ returns (bytes32 winnerName_)
173
+ {
174
+ winnerName_ = proposals[winningProposal()].name;
175
+ }
176
+ }
polygon/tests/Ballot_test.sol ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // SPDX-License-Identifier: GPL-3.0
2
+
3
+ pragma solidity >=0.7.0 <0.9.0;
4
+ import "remix_tests.sol"; // this import is automatically injected by Remix.
5
+ import "hardhat/console.sol";
6
+ import "../contracts/3_Ballot.sol";
7
+
8
+ contract BallotTest {
9
+
10
+ bytes32[] proposalNames;
11
+
12
+ Ballot ballotToTest;
13
+ function beforeAll () public {
14
+ proposalNames.push(bytes32("candidate1"));
15
+ ballotToTest = new Ballot(proposalNames);
16
+ }
17
+
18
+ function checkWinningProposal () public {
19
+ console.log("Running checkWinningProposal");
20
+ ballotToTest.vote(0);
21
+ Assert.equal(ballotToTest.winningProposal(), uint(0), "proposal at index 0 should be the winning proposal");
22
+ Assert.equal(ballotToTest.winnerName(), bytes32("candidate1"), "candidate1 should be the winner name");
23
+ }
24
+
25
+ function checkWinninProposalWithReturnValue () public view returns (bool) {
26
+ return ballotToTest.winningProposal() == 0;
27
+ }
28
+ }