paijo77 commited on
Commit
b778408
·
verified ·
1 Parent(s): ad09154

update app/db_models.py

Browse files
Files changed (1) hide show
  1. app/db_models.py +230 -0
app/db_models.py ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sqlalchemy import (
2
+ Column,
3
+ Integer,
4
+ String,
5
+ Boolean,
6
+ Float,
7
+ Text,
8
+ DateTime,
9
+ ForeignKey,
10
+ Index,
11
+ JSON,
12
+ )
13
+ from sqlalchemy.orm import relationship
14
+ from sqlalchemy.sql import func
15
+ from app.database import Base
16
+
17
+
18
+ class User(Base):
19
+ __tablename__ = "users"
20
+
21
+ id = Column(Integer, primary_key=True, index=True)
22
+ oauth_provider = Column(String(20), nullable=False)
23
+ oauth_id = Column(String(100), nullable=False, unique=True, index=True)
24
+ email = Column(String(255), nullable=False)
25
+ username = Column(String(100), nullable=False)
26
+ avatar_url = Column(Text, nullable=True)
27
+ role = Column(String(20), default="user", nullable=False)
28
+ created_at = Column(DateTime(timezone=True), server_default=func.now())
29
+ last_login = Column(DateTime(timezone=True), nullable=True)
30
+
31
+ sources = relationship(
32
+ "ProxySource", back_populates="owner", cascade="all, delete-orphan"
33
+ )
34
+
35
+ __table_args__ = (
36
+ Index("idx_oauth_provider_id", "oauth_provider", "oauth_id", unique=True),
37
+ )
38
+
39
+
40
+ class ProxySource(Base):
41
+ __tablename__ = "proxy_sources"
42
+
43
+ id = Column(Integer, primary_key=True, index=True)
44
+ user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=True)
45
+ url = Column(Text, nullable=False, unique=True, index=True)
46
+ type = Column(String(50), nullable=False)
47
+ name = Column(String(200), nullable=True)
48
+ description = Column(Text, nullable=True)
49
+ is_paid = Column(Boolean, default=False)
50
+ enabled = Column(Boolean, default=True, index=True)
51
+ validated = Column(Boolean, default=False)
52
+ validation_error = Column(Text, nullable=True)
53
+ created_at = Column(DateTime(timezone=True), server_default=func.now())
54
+ updated_at = Column(
55
+ DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
56
+ )
57
+ last_scraped = Column(DateTime(timezone=True), nullable=True)
58
+ total_scraped = Column(Integer, default=0)
59
+ success_rate = Column(Float, default=0.0)
60
+ is_admin_source = Column(Boolean, default=False)
61
+
62
+ owner = relationship("User", back_populates="sources")
63
+ proxies = relationship("Proxy", back_populates="source")
64
+
65
+
66
+ class Proxy(Base):
67
+ __tablename__ = "proxies"
68
+
69
+ id = Column(Integer, primary_key=True, index=True)
70
+ source_id = Column(
71
+ Integer, ForeignKey("proxy_sources.id", ondelete="SET NULL"), nullable=True
72
+ )
73
+ url = Column(Text, nullable=False, unique=True, index=True)
74
+ protocol = Column(String(50), nullable=False, index=True)
75
+ ip = Column(String(50), nullable=True)
76
+ port = Column(Integer, nullable=True)
77
+ country_code = Column(String(2), nullable=True, index=True)
78
+ country_name = Column(String(100), nullable=True)
79
+ state = Column(String(100), nullable=True)
80
+ city = Column(String(100), nullable=True)
81
+
82
+ latency_ms = Column(Integer, nullable=True, index=True)
83
+ speed_mbps = Column(Float, nullable=True)
84
+ uptime_percent = Column(Float, nullable=True)
85
+
86
+ anonymity = Column(String(20), nullable=True, index=True)
87
+ proxy_type = Column(String(20), nullable=True)
88
+ can_access_google = Column(Boolean, nullable=True)
89
+ quality_score = Column(Integer, nullable=True, index=True)
90
+
91
+ validation_status = Column(
92
+ String(20), default="pending", nullable=False, index=True
93
+ ) # pending, validating, validated, failed
94
+ last_validated = Column(DateTime(timezone=True), nullable=True)
95
+ validation_failures = Column(Integer, default=0)
96
+ is_working = Column(Boolean, default=True, index=True)
97
+
98
+ created_at = Column(DateTime(timezone=True), server_default=func.now())
99
+ updated_at = Column(
100
+ DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
101
+ )
102
+ first_seen = Column(DateTime(timezone=True), server_default=func.now())
103
+ last_seen = Column(DateTime(timezone=True), server_default=func.now())
104
+
105
+ source = relationship("ProxySource", back_populates="proxies")
106
+ validation_history = relationship(
107
+ "ValidationHistory", back_populates="proxy", cascade="all, delete-orphan"
108
+ )
109
+
110
+ __table_args__ = (
111
+ Index(
112
+ "idx_proxy_working_status_quality",
113
+ "is_working",
114
+ "validation_status",
115
+ "quality_score",
116
+ ),
117
+ )
118
+
119
+
120
+ class ValidationHistory(Base):
121
+ __tablename__ = "validation_history"
122
+
123
+ id = Column(Integer, primary_key=True, index=True)
124
+ proxy_id = Column(
125
+ Integer,
126
+ ForeignKey("proxies.id", ondelete="CASCADE"),
127
+ nullable=False,
128
+ index=True,
129
+ )
130
+ validated_at = Column(
131
+ DateTime(timezone=True), server_default=func.now(), index=True
132
+ )
133
+ latency_ms = Column(Integer, nullable=True)
134
+ anonymity = Column(String(20), nullable=True)
135
+ can_access_google = Column(Boolean, nullable=True)
136
+ success = Column(Boolean, nullable=False)
137
+ error_message = Column(Text, nullable=True)
138
+
139
+ proxy = relationship("Proxy", back_populates="validation_history")
140
+
141
+
142
+ class CandidateSource(Base):
143
+ __tablename__ = "candidate_sources"
144
+
145
+ id = Column(Integer, primary_key=True, index=True)
146
+ url = Column(Text, nullable=False, unique=True, index=True)
147
+ domain = Column(String(255), nullable=True, index=True)
148
+ discovery_method = Column(String(50), nullable=False) # github, search, ai
149
+ status = Column(
150
+ String(20), default="pending", nullable=False, index=True
151
+ ) # pending, validating, approved, rejected
152
+ confidence_score = Column(Integer, default=0, index=True)
153
+ proxies_found_count = Column(Integer, default=0)
154
+ last_checked_at = Column(DateTime(timezone=True), nullable=True)
155
+ created_at = Column(DateTime(timezone=True), server_default=func.now())
156
+ fail_count = Column(Integer, default=0)
157
+ meta_data = Column(JSON, nullable=True)
158
+
159
+ __table_args__ = (
160
+ Index("idx_candidate_status_score", "status", "confidence_score"),
161
+ )
162
+
163
+
164
+ class Notification(Base):
165
+ __tablename__ = "notifications"
166
+
167
+ id = Column(Integer, primary_key=True, index=True)
168
+ user_id = Column(
169
+ Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True
170
+ )
171
+ type = Column(String(50), nullable=False, index=True)
172
+ title = Column(String(255), nullable=False)
173
+ message = Column(Text, nullable=False)
174
+ severity = Column(String(20), default="info", nullable=False)
175
+ created_at = Column(DateTime(timezone=True), server_default=func.now(), index=True)
176
+ read = Column(Boolean, default=False, index=True)
177
+
178
+ user = relationship("User", backref="notifications")
179
+
180
+
181
+ class ScrapingSession(Base):
182
+ __tablename__ = "scraping_sessions"
183
+
184
+ id = Column(Integer, primary_key=True, index=True)
185
+ source_id = Column(
186
+ Integer,
187
+ ForeignKey("proxy_sources.id", ondelete="CASCADE"),
188
+ nullable=False,
189
+ index=True,
190
+ )
191
+ scraping_type = Column(String(50), default="scheduled", nullable=False)
192
+ status = Column(String(20), default="running", nullable=False, index=True)
193
+ proxies_found = Column(Integer, default=0)
194
+ proxies_valid = Column(Integer, default=0)
195
+ config = Column(JSON, nullable=True)
196
+ error_message = Column(Text, nullable=True)
197
+ initiated_by = Column(
198
+ Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True
199
+ )
200
+ started_at = Column(DateTime(timezone=True), server_default=func.now(), index=True)
201
+ finished_at = Column(DateTime(timezone=True), nullable=True)
202
+
203
+ source = relationship("ProxySource")
204
+ initiator = relationship("User")
205
+
206
+ __table_args__ = (
207
+ Index("idx_scraping_session_status_source", "status", "source_id"),
208
+ )
209
+
210
+
211
+ class BackgroundTask(Base):
212
+ __tablename__ = "background_tasks"
213
+
214
+ id = Column(Integer, primary_key=True, index=True)
215
+ task_type = Column(String(100), nullable=False, index=True)
216
+ task_data = Column(JSON, nullable=False)
217
+ status = Column(String(20), default="pending", nullable=False, index=True)
218
+ result = Column(JSON, nullable=True)
219
+ error_message = Column(Text, nullable=True)
220
+ retry_count = Column(Integer, default=0)
221
+ max_retries = Column(Integer, default=3)
222
+ scheduled_for = Column(
223
+ DateTime(timezone=True), server_default=func.now(), index=True
224
+ )
225
+ started_at = Column(DateTime(timezone=True), nullable=True)
226
+ completed_at = Column(DateTime(timezone=True), nullable=True)
227
+
228
+ __table_args__ = (
229
+ Index("idx_background_task_status_scheduled", "status", "scheduled_for"),
230
+ )