From 9a325f29da7707efae88ab317b19181d2987891b Mon Sep 17 00:00:00 2001 From: Sun Date: Fri, 8 Oct 2021 17:01:46 +0800 Subject: [PATCH] domain add active & deletable --- lib/apps/domain/models.dart | 1 + lib/apps/domain/page.dart | 82 +++++++++++++++++++++++++++------- lib/l10n/localizations.dart | 5 +++ lib/l10n/localizations_en.dart | 11 +++++ lib/l10n/localizations_zh.dart | 11 +++++ src/apps/domain/layer.rs | 20 ++++++++- src/apps/domain/models.rs | 46 +++++++++++++------ src/apps/domain/rpc.rs | 62 ++++++++++++++++++++----- 8 files changed, 195 insertions(+), 43 deletions(-) diff --git a/lib/apps/domain/models.dart b/lib/apps/domain/models.dart index d736b7f..574d980 100644 --- a/lib/apps/domain/models.dart +++ b/lib/apps/domain/models.dart @@ -6,6 +6,7 @@ class ProviderServer { bool isDefault; bool isProxy; bool isActived; + bool deletable = true; ProviderServer.empty(): this.id = 0, diff --git a/lib/apps/domain/page.dart b/lib/apps/domain/page.dart index 2d12d31..9bca71c 100644 --- a/lib/apps/domain/page.dart +++ b/lib/apps/domain/page.dart @@ -39,7 +39,9 @@ class _DomainDetailState extends State { }); this._names.clear(); params[1].forEach((param) { - this._names.add(Name.fromList(param)); + final name = Name.fromList(param); + this._providers[name.provider]!.deletable = false; + this._names.add(name); }); setState(() {}); } @@ -146,6 +148,7 @@ class _ListNameScreen extends StatefulWidget { } class _ListNameScreenState extends State<_ListNameScreen> { + bool _deleteTime = false; List<_NameItem> _data = []; @override @@ -153,7 +156,7 @@ class _ListNameScreenState extends State<_ListNameScreen> { final color = Theme.of(context).colorScheme; final lang = AppLocalizations.of(context); - if (this._data.length != widget.names.length) { + if (!this._deleteTime && this._data.length != widget.names.length) { this._data = widget.names.map((name) { return _NameItem( name: name, @@ -161,6 +164,7 @@ class _ListNameScreenState extends State<_ListNameScreen> { ); }).toList(); } + this._deleteTime = false; return ExpansionPanelList( elevation: 0.0, @@ -171,6 +175,7 @@ class _ListNameScreenState extends State<_ListNameScreen> { }, children: _data.map((_NameItem item) { return ExpansionPanel( + backgroundColor: color.surface, headerBuilder: (BuildContext context, bool isExpanded) { return ListTile( contentPadding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 8.0), @@ -196,17 +201,36 @@ class _ListNameScreenState extends State<_ListNameScreen> { leading: Icon(Icons.location_on), title: Text(item.provider.name), ), - ListTile( - leading: Icon(Icons.cancel, color: color.primary), - title: Text('Set to unactived ?', style: TextStyle(color: color.primary)), + item.name.isActived + ? ListTile( + leading: Icon(Icons.cancel, color: Colors.orange), + title: Text(lang.domainSetUnactived, style: TextStyle(color: Colors.orange)), + onTap: () { + rpc.send('domain-active', [item.name.name, item.provider.addr, false]); + setState(() { + item.name.isActived = false; + item.isExpanded = false; + }); + }) + : ListTile( + leading: Icon(Icons.done, color: color.primary), + title: Text(lang.domainSetActived, style: TextStyle(color: color.primary)), onTap: () { - // + rpc.send('domain-active', [item.name.name, item.provider.addr, true]); + setState(() { + item.name.isActived = true; + item.isExpanded = false; + }); }), ListTile( leading: const Icon(Icons.delete, color: Colors.red), - title: Text('Delete from provider ?', style: TextStyle(color: Colors.red)), + title: Text(lang.domainDelete, style: TextStyle(color: Colors.red)), onTap: () { - // + rpc.send('domain-remove', [item.name.name, item.provider.addr]); + setState(() { + this._data.removeWhere((_NameItem currentItem) => item == currentItem); + this._deleteTime = true; + }); }), ] ), @@ -241,23 +265,26 @@ class _ListProviderScreen extends StatelessWidget { const _ListProviderScreen(this.providers); - Widget _providerItem(int id, String name, String address, bool isDefault, ColorScheme color, AppLocalizations lang) { + Widget _providerItem(ProviderServer provider, ColorScheme color, AppLocalizations lang, context) { return Container( margin: const EdgeInsets.only(bottom: 10.0), decoration: BoxDecoration(color: color.surface), child: ListTile( contentPadding: EdgeInsets.symmetric(vertical: 4.0), leading: Tooltip( - message: 'set default ?', + message: lang.domainSetDefault, child: TextButton( - child: Icon(Icons.check_circle, color: isDefault ? Color(0xFF6174FF) : Colors.grey), - onPressed: () {} + child: Icon(Icons.check_circle, color: provider.isDefault ? Color(0xFF6174FF) : Colors.grey), + onPressed: () { + rpc.send('domain-provider-default', [provider.id]); + rpc.send('domain-list', []); + } ), ), - title: Text(name, style: TextStyle(fontWeight: FontWeight.bold)), + title: Text(provider.name, style: TextStyle(fontWeight: FontWeight.bold)), subtitle: Row( children: [ - Expanded(child: Text(address, style: TextStyle(fontSize: 14.0))), + Expanded(child: Text(addrPrint(provider.addr), style: TextStyle(fontSize: 14.0))), ], ), trailing: Container( @@ -265,8 +292,29 @@ class _ListProviderScreen extends StatelessWidget { decoration: new BoxDecoration( border: new Border(left: const BorderSide(width: 1.0, color: Color(0xA0ADB0BB)))), child: TextButton( - child: Icon(Icons.delete, color: Colors.red), - onPressed: () {} + child: Icon(Icons.delete, color: provider.deletable ? Colors.red : Colors.grey), + onPressed: provider.deletable ? () => showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text(lang.delete + " ${provider.name} ?"), + actions: [ + TextButton( + child: Text(lang.cancel), + onPressed: () => Navigator.pop(context), + ), + TextButton( + child: Text(lang.ok), + onPressed: () { + Navigator.pop(context); + rpc.send('domain-provider-remove', [provider.id]); + rpc.send('domain-list', []); + }, + ), + ] + ); + }, + ) : null )), ) ); @@ -279,7 +327,7 @@ class _ListProviderScreen extends StatelessWidget { return Column( children: this.providers.values.map( - (provider) => _providerItem(provider.id, provider.name, addrPrint(provider.addr), provider.isDefault, color, lang) + (provider) => _providerItem(provider, color, lang, context) ).toList(), ); } diff --git a/lib/l10n/localizations.dart b/lib/l10n/localizations.dart index c38f694..d7c5ca7 100644 --- a/lib/l10n/localizations.dart +++ b/lib/l10n/localizations.dart @@ -217,6 +217,11 @@ abstract class AppLocalizations { String get domainAddProvider; String get domainSearch; String get domainRegisterFailure; + String get domainSetDefault; + String get domainSetUnactived; + String get domainSetActived; + String get domainDelete; + String get domainNotDelete; String get cloud; String get cloudIntro; diff --git a/lib/l10n/localizations_en.dart b/lib/l10n/localizations_en.dart index e773614..08ea8bd 100644 --- a/lib/l10n/localizations_en.dart +++ b/lib/l10n/localizations_en.dart @@ -339,6 +339,17 @@ class AppLocalizationsEn extends AppLocalizations { String get domainSearch => 'Public ID Search'; @override String get domainRegisterFailure => 'username already existed!'; + @override + String get domainSetDefault => 'Set default ?'; + @override + String get domainSetUnactived => 'Set to unactived ?'; + @override + String get domainSetActived => 'Set to actived ?'; + @override + String get domainDelete => 'Delete from provider ?'; + @override + String get domainNotDelete => 'Had ID, cannot delete'; + @override String get cloud => 'Cloud Peer'; @override diff --git a/lib/l10n/localizations_zh.dart b/lib/l10n/localizations_zh.dart index e0b133b..57fd772 100644 --- a/lib/l10n/localizations_zh.dart +++ b/lib/l10n/localizations_zh.dart @@ -339,6 +339,17 @@ class AppLocalizationsZh extends AppLocalizations { String get domainSearch => '个人ID搜索'; @override String get domainRegisterFailure => '用户名已存在!'; + @override + String get domainSetDefault => '设为默认?'; + @override + String get domainSetUnactived => '设为暂停状态?'; + @override + String get domainSetActived => '设为正常状态?'; + @override + String get domainDelete => '从站点中删除?'; + @override + String get domainNotDelete => '有注册ID,无法删除'; + @override String get cloud => '云节点'; @override diff --git a/src/apps/domain/layer.rs b/src/apps/domain/layer.rs index 865f441..b7d4e9e 100644 --- a/src/apps/domain/layer.rs +++ b/src/apps/domain/layer.rs @@ -51,7 +51,7 @@ pub(crate) async fn handle( user.is_actived = true; results.rpcs.push(rpc::register_success(ogid, &user)); } else { - Name::delete(&db, &user.id)?; + user.delete(&db)?; results.rpcs.push(rpc::register_failure(ogid, &name)); } } @@ -63,6 +63,24 @@ pub(crate) async fn handle( ServerEvent::None(uname) => { results.rpcs.push(rpc::search_none(ogid, &uname)); } + ServerEvent::Actived(uname, is_actived) => { + let provider = Provider::get_by_addr(&db, &addr)?; + let name = Name::get_by_name_provider(&db, &uname, &provider.id)?; + Name::active(&db, &name.id, is_actived)?; + + let ps = Provider::list(&db)?; + let names = Name::list(&db)?; + results.rpcs.push(rpc::domain_list(ogid, &ps, &names)); + } + ServerEvent::Deleted(uname) => { + let provider = Provider::get_by_addr(&db, &addr)?; + let name = Name::get_by_name_provider(&db, &uname, &provider.id)?; + name.delete(&db)?; + + let ps = Provider::list(&db)?; + let names = Name::list(&db)?; + results.rpcs.push(rpc::domain_list(ogid, &ps, &names)); + } ServerEvent::Response(_ugid, _uname, _is_ok) => {} } } diff --git a/src/apps/domain/models.rs b/src/apps/domain/models.rs index ec39bc9..f7b2f92 100644 --- a/src/apps/domain/models.rs +++ b/src/apps/domain/models.rs @@ -11,7 +11,7 @@ pub(crate) struct Provider { /// name. name: String, /// address. - addr: PeerAddr, + pub addr: PeerAddr, /// is add ok. is_ok: bool, /// is default. @@ -85,6 +85,16 @@ impl Provider { Err(anyhow!("provider is missing")) } + /// use in rpc when load provider by id. + pub fn get_default(db: &DStorage) -> Result { + let mut matrix = db.query("SELECT id, name, addr, is_ok, is_default, is_proxy, is_actived FROM providers WHERE is_default = true")?; + if matrix.len() > 0 { + let values = matrix.pop().unwrap(); // safe unwrap() + return Ok(Self::from_values(values)); + } + Err(anyhow!("provider is missing")) + } + /// insert a new provider. pub fn get_by_addr(db: &DStorage, addr: &PeerAddr) -> Result { let sql = format!( @@ -148,6 +158,16 @@ impl Provider { Ok(()) } + /// return if is closed + pub fn default(&self, db: &DStorage, default: bool) -> Result<()> { + let sql = format!( + "UPDATE providers SET is_default = {} WHERE id = {}", + default, self.id + ); + db.update(&sql)?; + Ok(()) + } + /// return if is closed pub fn delete(db: &DStorage, id: &i64) -> Result<()> { let sql = format!("UPDATE providers SET is_actived = false WHERE id = {}", id); @@ -161,7 +181,7 @@ pub(crate) struct Name { /// db auto-increment id. pub id: i64, /// provider database id. - provider: i64, + pub provider: i64, /// name. pub name: String, /// bio. @@ -218,18 +238,18 @@ impl Name { Ok(names) } - /// use in rpc when load provider by id. - pub fn get(db: &DStorage, id: &i64) -> Result { + /// get name register. + pub fn get_by_provider(db: &DStorage, provider: &i64) -> Result> { let sql = format!( - "SELECT id, provider, name, bio, is_ok, is_actived FROM names WHERE id = {}", - id + "SELECT id, provider, name, bio, is_ok, is_actived FROM names WHERE provider = {}", + provider ); - let mut matrix = db.query(&sql)?; - if matrix.len() > 0 { - let values = matrix.pop().unwrap(); // safe unwrap() - return Ok(Self::from_values(values)); + let matrix = db.query(&sql)?; + let mut names = vec![]; + for values in matrix { + names.push(Self::from_values(values)); } - Err(anyhow!("name is missing")) + Ok(names) } /// get name register. @@ -275,8 +295,8 @@ impl Name { } /// delete the name. - pub fn delete(db: &DStorage, id: &i64) -> Result<()> { - let sql = format!("DELETE names WHERE id = {}", id); + pub fn delete(&self, db: &DStorage) -> Result<()> { + let sql = format!("DELETE names WHERE id = {}", self.id); db.delete(&sql)?; Ok(()) } diff --git a/src/apps/domain/rpc.rs b/src/apps/domain/rpc.rs index c4c21ee..42e4d46 100644 --- a/src/apps/domain/rpc.rs +++ b/src/apps/domain/rpc.rs @@ -28,6 +28,13 @@ pub(crate) fn register_failure(mgid: GroupId, name: &str) -> RpcParam { rpc_response(0, "domain-register-failure", json!([name]), mgid) } +#[inline] +pub(crate) fn domain_list(mgid: GroupId, providers: &[Provider], names: &[Name]) -> RpcParam { + let providers: Vec = providers.iter().map(|p| p.to_rpc()).collect(); + let names: Vec = names.iter().map(|p| p.to_rpc()).collect(); + rpc_response(0, "domain-list", json!([providers, names]), mgid) +} + #[inline] pub(crate) fn search_result( mgid: GroupId, @@ -94,19 +101,35 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "domain-provider-default", - |_gid: GroupId, params: Vec, _state: Arc| async move { - let _id = params[0].as_i64().ok_or(RpcError::ParseError)?; + |gid: GroupId, params: Vec, state: Arc| async move { + let id = params[0].as_i64().ok_or(RpcError::ParseError)?; + + let db = domain_db(state.layer.read().await.base(), &gid)?; + let provider = Provider::get(&db, &id)?; + if let Ok(default) = Provider::get_default(&db) { + if default.id == provider.id { + return Ok(HandleResult::new()); + } + default.default(&db, false)?; + } + provider.default(&db, true)?; - Ok(HandleResult::rpc(json!(params))) + Ok(HandleResult::new()) }, ); handler.add_method( "domain-provider-remove", - |_gid: GroupId, params: Vec, _state: Arc| async move { - let _id = params[0].as_i64().ok_or(RpcError::ParseError)?; + |gid: GroupId, params: Vec, state: Arc| async move { + let id = params[0].as_i64().ok_or(RpcError::ParseError)?; + + let db = domain_db(state.layer.read().await.base(), &gid)?; + let names = Name::get_by_provider(&db, &id)?; + if names.len() == 0 { + Provider::delete(&db, &id)?; + } - Ok(HandleResult::rpc(json!(params))) + Ok(HandleResult::new()) }, ); @@ -135,19 +158,34 @@ pub(crate) fn new_rpc_handler(handler: &mut RpcHandler) { handler.add_method( "domain-active", - |_gid: GroupId, params: Vec, _state: Arc| async move { - let _id = params[0].as_i64().ok_or(RpcError::ParseError)?; + |gid: GroupId, params: Vec, _state: Arc| async move { + let name = params[0].as_str().ok_or(RpcError::ParseError)?.to_owned(); + let provider = PeerAddr::from_hex(params[1].as_str().ok_or(RpcError::ParseError)?)?; + let active = params[2].as_bool().ok_or(RpcError::ParseError)?; + + let mut results = HandleResult::new(); + let event = if active { + PeerEvent::Active(name) + } else { + PeerEvent::Suspend(name) + }; + add_layer(&mut results, provider, event, gid)?; - Ok(HandleResult::rpc(json!(params))) + Ok(results) }, ); handler.add_method( "domain-remove", - |_gid: GroupId, params: Vec, _state: Arc| async move { - let _id = params[0].as_i64().ok_or(RpcError::ParseError)?; + |gid: GroupId, params: Vec, _state: Arc| async move { + let name = params[0].as_str().ok_or(RpcError::ParseError)?.to_owned(); + let provider = PeerAddr::from_hex(params[1].as_str().ok_or(RpcError::ParseError)?)?; - Ok(HandleResult::rpc(json!(params))) + let mut results = HandleResult::new(); + let event = PeerEvent::Delete(name); + add_layer(&mut results, provider, event, gid)?; + + Ok(results) }, );