visuddhinanda 2 недель назад
Родитель
Сommit
b3217ff9ab

+ 16 - 7
api-v13/.env.example

@@ -11,7 +11,7 @@ APP_FAKER_LOCALE=en_US
 APP_MAINTENANCE_DRIVER=file
 # APP_MAINTENANCE_STORE=database
 
-# PHP_CLI_SERVER_WORKERS=4
+PHP_CLI_SERVER_WORKERS=4
 
 BCRYPT_ROUNDS=12
 
@@ -20,12 +20,12 @@ LOG_STACK=single
 LOG_DEPRECATIONS_CHANNEL=null
 LOG_LEVEL=debug
 
-DB_CONNECTION=sqlite
-# DB_HOST=127.0.0.1
-# DB_PORT=3306
-# DB_DATABASE=laravel
-# DB_USERNAME=root
-# DB_PASSWORD=
+DB_CONNECTION=pgsql
+DB_HOST=127.0.0.1
+DB_PORT=5432
+DB_DATABASE=mint
+DB_USERNAME=root
+DB_PASSWORD=
 
 SESSION_DRIVER=database
 SESSION_LIFETIME=120
@@ -63,3 +63,12 @@ AWS_BUCKET=
 AWS_USE_PATH_STYLE_ENDPOINT=false
 
 VITE_APP_NAME="${APP_NAME}"
+
+OPENSEARCH_SCHEME=http
+OPENSEARCH_HOST=127.0.0.1
+OPENSEARCH_PORT=9200
+OPENSEARCH_USERNAME=""
+OPENSEARCH_PASSWORD=""
+OPENSEARCH_SSL_VERIFICATION=false
+
+JWT_SECRETS_KEY=

+ 86 - 0
api-v13/documents/mobile/privacy/children.md

@@ -0,0 +1,86 @@
+## wikipali app儿童个人信息保护规则及监护人须知
+ 
+
+有宜良县云台文化与生态保护协会深知儿童(未满十四周岁,下同)个人信息和隐私安全的重要性。我们希望通过《wikipali app儿童个人信息保护规则及监护人须知》(以下简称“本政策”)说明我们在收集和使用儿童个人信息时对应的处理规则等相关事宜。在使用我们的wikipali app服务前,请儿童、儿童的父母或其他监护人务必仔细阅读并透彻理解本政策,在确认充分理解并同意全部条款后再开始使用。
+
+**监护人特别说明:**
+
+若我们获悉您的孩子不满十四周岁,我们将根据本政策采取特殊措施保护我们获得的您孩子的个人信息。请帮助我们保护您孩子的个人信息和隐私安全,要求他们在您的监护下共同阅读并接受本政策,且应在您的同意和指导下使用wikipali app服务、提交个人信息。如果您不同意本政策的内容,将可能导致我们的产品和服务无法正常运行,或者无法达到我们拟达到的服务效果,您应要求您的孩子立即停止访问/使用wikipali app服务。您点击同意本政策,或者您的孩子使用/继续使用wikipali app服务
+、提交个人信息,都表示您同意我们按照本政策(包括更新版本)收集、使用、储存和分享您孩子的个人信息。如果您不同意本政策的内容,请您要求您的孩子立即停止访问/使用我们的产品及服务。
+
+**儿童特别说明:**
+
+我们建议:任何儿童参加网上活动都应事先取得监护人的同意。如果您是儿童,请通知您的监护人共同阅读本政策,并在您使用wikipali app服务、提交个人信息之前,寻求您的监护人的同意和指导。您点击同意本政策,或者您使用/继续使用wikipali app服务、提交个人信息,都表示您已获得您的监护人的许可,您的监护人均同意我们按照本政策(包括更新版本)收集、使用、储存和分享您的个人信息。
+
+本政策适用于我们在中华人民共和国境内通过网络从事收集、使用、储存和分享儿童个人信息等活动。当儿童使用wikipali app服务时,监护人同意接受本政策以及我们在该单项服务中发出的特定儿童个人信息保护类规则条款(如有,以下称“特定条款”)的保护,在此情况下特定条款与本政策条款同时对监护人和儿童产生效力。如特定条款与本政策条款存在同类条款的不一致约定,则在特定条款约束范围内应以特定条款为准。如我们提供的某一单项服务不适用本政策的,该服务中会以适当方式明示排除适用本政策。在儿童个人信息保护规则方面,本政策与《wikipali app隐私政策》正文不一致的,本政策优先适用,如本政策中未提及的,,则以《wikipali app隐私政策》为准。
+
+在阅读完本政策后,如对本政策或与本政策相关的事宜有任何问题,可通过本政策“如何联系我们”章节所列的反馈渠道联系我们,我们会尽快作出解答。
+
+
+目录
+
+- 一、我们如何收集和使用儿童个人信息
+- 二、我们如何使用COOKIES或同类技术
+- 三、我们可能共享、转让和披露的儿童个人信息
+- 四、我们如何保留、储存和保护儿童个人信息
+- 五、如何管理儿童个人信息
+- 六、本政策如何更新
+- 七、如何联系我们
+ 
+
+一、我们如何收集和使用儿童个人信息
+
+《wikipali app隐私政策》阐述了我们通常的个人信息收集做法。我们会出于以下目的,在征得监护人的同意后,收集和使用儿童以下类型的个人信息:
+
+1、位置信息、设备信息
+
+为便于我们提供服务,儿童需要提供基本位置信息、设备信息。将用于为儿童提供明相日中时间计算服务、反馈建议服务等。 
+如果仅需使用基本服务,儿童不需要提供上述信息。
+
+二、我们如何使用COOKIES或同类技术
+
+(一)本地存储器
+为确保app正常运转,我们会在儿童的计算机或移动设备上存储必要的数据文件。通常包含app版本信息、词典文件、巴利文献文件等。
+我们不会将本地存储用于本政策所述目的之外的任何用途。儿童可根据自己的偏好管理或删除 本地存储文件。但如果儿童这么做,相关功能将无法使用。
+
+三、我们可能共享、转让或披露的儿童个人信息
+
+(一)共享
+我们不会与其他的任何公司、组织和个人分享您的用户信息。
+(二)转让
+我们不会将您的用户信息转让给任何公司、组织和个人。
+(三)共享、转让、披露信息时事先征得授权同意的例外
+
+以下情形中,分享、转让、披露儿童的信息无需事先征得监护人的授权同意:
+
+1、与个人信息控制者履行法律法规规定的义务相关的;
+2、与国家安全、国防安全有关的;
+3、与公共安全、公共卫生、重大公共利益有关的;
+4、与刑事侦查、起诉、审判和判决执行等司法或行政执法有关的;
+5、出于维护儿童或其他个人的生命、财产等重大合法权益但又很难得到监护人同意的;
+6、儿童或监护人自行向社会公众公开的信息;
+7、从合法公开披露的信息中收集信息的,如合法的新闻报道、政府信息公开等渠道。
+根据法律规定,共享、转让、披露经去标识化处理的个人信息,且确保数据接收方无法复原并重新识别信息主体的,不属于个人信息的对外共享、转让及公开披露行为,对此类数据的保存及处理将无需另行向监护人通知并征得监护人的同意。
+
+四、我们如何保留、储存和保护儿童个人信息
+
+我们仅在本政策所述目的所必需期间和法律法规要求的最短时限内保留儿童个人信息。如我们终止服务或运营,我们将及时停止继续收集儿童个人信息的活动,同时会遵守相关法律法规要求提前向监护人通知,并在终止服务或运营后对儿童的个人信息进行删除或匿名化处理,但法律法规或监管部门另有规定的除外。
+
+我们在中华人民共和国境内运营中收集和产生的儿童个人信息,存储在中国境内,以下情形除外:
+
+1、法律法规有明确规定;
+
+2、获得监护人的授权同意;
+
+3、儿童使用的产品、服务涉及跨境,wikipali app需要向境外提供儿童个人信息的。
+
+针对以上情形,我们会进行安全评估,并确保依据本政策及国家法律法规要求对儿童个人信息提供足够的保护。
+
+(一)我们会采取一切合理可行的措施,确保未收集无关的儿童个人信息。
+(二)互联网并非绝对安全的环境,而且电子邮件、即时通讯、及与其他用户的交流方式并未加密,我们强烈建议您不要通过此类方式发送用户信息。
+(三)互联网环境并非百分之百安全,我们将尽力确保您发送给我们的任何信息的安全性。即使我们做出了很大努力,采取了一切合理且必要的措施,仍然有可能无法杜绝您的用户信息被非法访问、被非法盗取,被非法篡改或毁坏,导致您的合法权益受损,请您理解信息网络的上述风险并自愿承担。
+(四)在不幸发生用户信息安全事件后,我们将按照法律法规的要求,及时向您告知:安全事件的基本情况和可能的影响、我们已采取或将要采取的处置措施、您可自主防范和降低风险的建议、对您的补救措施等。我们将及时将事件相关情况以邮件、信函、电话、推送通知等方式告知您,难以逐一告知用户信息主体时,我们会采取合理、有效的方式发布公告。同时,我们还将按照监管部门要求,主动上报用户信息安全事件的处置情况。
+
+五、如何管理儿童个人信息
+
+我们非常重视儿童个人信息的保护。尽管当地法律和习俗对儿童的定义不同,但我们将不满 14 周岁的任何人均视为儿

+ 102 - 0
api-v13/documents/mobile/privacy/index.md

@@ -0,0 +1,102 @@
+本政策仅适用于宜良县云台文化与生态保护协会的wikipali app产品或服务。 
+最近更新日期:2023年9月29日
+
+本政策将帮助您了解以下内容:
+- 一、我们如何收集和使用您的用户信息
+- 二、我们如何使用 Cookie 和同类技术
+- 三、我们如何共享、转让、公开披露您的用户信息
+- 四、我们如何保护您的用户信息
+- 五、您的权利
+- 六、我们如何处理儿童的个人信息
+- 七、本政策如何更新
+- 八、如何联系我们
+
+我们深知用户信息对您的重要性,并会尽全力保护您的用户信息安全可靠。我们致力于维持您对我们的信任,恪守以下原则,保护您的用户信息:权责一致原则、目的明确原则、选择同意原则、最少够用原则、确保安全原则、主体参与原则、公开透明原则等。同时,我们承诺,我们将按业界成熟的安全标准,采取相应的安全保护措施来保护您的用户信息。
+请在使用我们的产品(或服务)前,仔细阅读并了解本隐私政策。
+
+**一、我们如何收集和使用您的用户信息**
+
+您使用我司产品或服务过程中我们收集和使用的信息
+我们仅会出于本政策所述的业务功能,收集和使用您的用户信息,收集用户信息的目的在于向您提供产品或服务,您有权自行选择是否提供该信息,但多数情况下,如果您不提供,我们可能无法向您提供相应的服务,也无法回应您遇到的问题:
+在您使用我们的服务时,允许我们收集您自行向我们提供的或为向您提供服务所必要的信息包括:位置信息、设备信息等。
+对于我们收集的个人信息,我们将用于为您提供明相日中时间计算服务、反馈建议服务等。 
+您提供的上述信息,将在您使用本服务期间持续授权我们使用。在您停止使用服务时,我们将停止使用并删除上述信息。
+我们保证会依法对收集后的用户信息进行去标识化或匿名化处理,对于无法单独或者与其他信息结合识别自然人个人身份的信息,不属于法律意义上的个人信息。如果我们将非个人信息与其他信息结合识别到您的个人身份时,或者与您的个人信息结合使用时,我们会在结合使用期间,将此类信息作为您的个人信息按照本隐私政策对其进行处理和保护。
+为了更好运营和改善我们的技术和服务,或出于商业策略的变化,当我们提供的产品或服务所需的用户信息收集、使用、处理超出上述范围或者要将收集到的用户信息用于本隐私政策未载明的其他用途,或当我们要将基于特定目的收集而来的信息用于其他目的时,我们会在获取用户信息后的合理期限内或处理用户信息前通知您,并获得您的授权同意。
+
+**二、我们如何使用 Cookie 和同类技术**
+
+(一)本地存储器
+为确保app正常运转,我们会在您的计算机或移动设备上存储名必要的数据文件。通常包含app版本信息、词典文件、巴利文献文件等。
+我们不会将本地存储用于本政策所述目的之外的任何用途。您可根据自己的偏好管理或删除 本地存储文件。但如果您这么做,相关功能将无法使用。
+
+**三、我们如何共享、转让、公开披露您的用户信息**
+
+(一)共享
+我们不会与其他的任何公司、组织和个人分享您的用户信息。
+
+(二)转让
+我们不会将您的用户信息转让给任何公司、组织和个人。
+
+(三)公开披露
+我们仅会在以下情况下,公开披露您的用户信息:
+1、基于法律的披露:在法律、法律程序、诉讼或政府主管部门强制性要求的情况下,我们可能会公开披露您的用户信息。
+
+(四)共享、转让、公开披露信息时事先征得授权同意的例外
+请您理解,根据法律法规及相关国家标准,以下情形中,我们共享、转让、公开披露您的用户信息无需征得您的授权同意:
+- 1、与国家安全、国防安全直接相关的; 
+- 2、与公共安全、公共卫生、重大公共利益直接相关的; 
+- 3、与犯罪侦查、起诉、审判和判决执行等直接相关的; 
+- 4、出于维护您或其他个人的生命、财产等重大合法权益但又很难得到本人同意的; 
+- 5、您自行向社会公众公开的信息; 
+- 6、从合法公开披露的信息中收集的,如合法的新闻报道、政府信息公开等渠道。
+
+**四、我们如何保护您的用户信息**
+
+- (一)我们已使用符合业界标准的安全防护措施保护您提供的用户信息,防止数据遭到未经授权的访问、公开披露、使用、修改、损坏或丢失。我们会采取一切合理可行的措施,保护您的用户信息。
+- (二)我们会采取一切合理可行的措施,确保未收集无关的用户信息。我们只会在达成本政策所述目的所需的期限内保留您的用户信息,除非需要延长保留期或受到法律的允许。
+- (三)互联网并非绝对安全的环境,而且电子邮件、即时通讯、及与其他用户的交流方式并未加密,我们强烈建议您不要通过此类方式发送用户信息。
+- (四)互联网环境并非百分之百安全,我们将尽力确保您发送给我们的任何信息的安全性。即使我们做出了很大努力,采取了一切合理且必要的措施,仍然有可能无法杜绝您的用户信息被非法访问、被非法盗取,被非法篡改或毁坏,导致您的合法权益受损,请您理解信息网络的上述风险并自愿承担。
+- (五)在不幸发生用户信息安全事件后,我们将按照法律法规的要求,及时向您告知:安全事件的基本情况和可能的影响、我们已采取或将要采取的处置措施、您可自主防范和降低风险的建议、对您的补救措施等。我们将及时将事件相关情况以邮件、信函、电话、推送通知等方式告知您,难以逐一告知用户信息主体时,我们会采取合理、有效的方式发布公告。同时,我们还将按照监管部门要求,主动上报用户信息安全事件的处置情况。
+
+**五、您的权利**
+
+按照中国相关的法律、法规、标准,以及其他国家、地区的通行做法,我们保障您对自己的用户信息行使以下权利:
+- (一)改变您授权同意的范围
+每个业务功能需要一些基本的用户信息才能得以完成(见本政策“第一部分”)。对于用户信息的收集和使用,您可以随时给予或收回您的授权同意。
+当您收回同意后,我们将不再处理相应的用户信息。同时也请您注意,您撤销授权同意可能会导致某些后果,例如我们可能无法继续为您提供相应的服务或特定的功能,但您收回同意的决定,不会影响此前基于您的授权而开展的用户信息处理。
+- (二·)约束信息系统自动决策
+在某些业务功能中,我们可能仅依据信息系统、算法等在内的非人工自动决策机制作出决定。如果这些决定显著影响您的合法权益,您有权要求我们作出解释,我们也将提供适当的救济方式。
+对于您合理的请求,我们原则上不收取费用。对于那些无端重复、需要过多技术手段(例如,需要开发新系统或从根本上改变现行惯例)、给他人合法权益带来风险或者非常不切实际的请求,我们可能会予以拒绝。也请您理解,出于安全保障的考虑、相关法律法规的要求或技术上的限制,对于您的某些请求我们可能无法做出响应,例如以下情形:
+  - 1、与用户信息控制者履行法律法规规定的义务相关的;
+  - 2、与国家安全、国防安全直接相关的;
+  - 3、与公共安全、公共卫生、重大公共利益直接相关的;
+  - 4、与犯罪侦查、起诉、审判和执行判决等直接相关的;
+  - 5、用户信息控制者有充分证据表明用户信息主体存在主观恶意或滥用权利的;
+  - 6、出于维护用户信息主体或其他个人的生命、财产等重大合法权益但又很难得到本人同意的;
+  - 7、响应用户信息主体的请求将导致用户信息主体或其他个人、组织的合法权益受到严重损害的; 
+  - 8、涉及商业秘密的。
+
+**六、我们如何处理儿童的个人信息**
+
+我们非常重视[儿童个人信息的保护](children/)。尽管当地法律和习俗对儿童的定义不同,但我们将不满 14 周岁的任何人均视为儿童。
+对于经父母或监护人同意而收集儿童用户信息的情况,我们只会在受到法律允许、父母或监护人明确同意或者保护儿童所必要的情况下储存、使用或公开披露此信息,否则我们会设法尽快删除相关数据。
+鉴于现有技术和业务模式的限制,我们很难主动识别儿童的个人信息,如果您发现我们在不知情的情况下或在未事先获得可证实的监护人同意的情况下收集了儿童的个人信息,您可以及时联系我们,我们将在发现后设法及时删除,如果我们自己发现前述情形的,我们也会及时删除,法律要求我们保留的除外。
+
+**七、本政策如何更新**
+
+我们的隐私政策可能变更。未经您明确同意,我们不会削减您按照本隐私政策所应享有的权利。我们会在本页面上发布对本政策所做的任何变更。
+对于重大变更,我们还会提供更为显著的通知。本政策所指的重大变更包括但不限于:
+1、我们的服务模式发生重大变化。如处理用户信息的目的、处理的用户信息类型、用户信息的使用方式等;
+2、我们在所有权结构、组织架构等方面发生重大变化。如业务调整等引起的所有者变更等;
+3、用户信息共享、转让或公开披露的主要对象发生变化;
+4、您参与用户信息处理方面的权利及其行使方式发生重大变化;
+5、我们负责处理用户信息安全的责任部门、联络方式及投诉渠道发生变化时;
+6、用户信息安全影响评估报告表明存在高风险时。
+我们还会将本政策的旧版本存档,供您查阅。
+
+**八、如何联系我们**
+
+如果您对本隐私政策有任何疑问、意见或建议,通过以下方式与我们联系:
+地址:云南省昆明市宜良县南羊街道办新庄村
+

+ 321 - 0
api-v13/routes/api.php

@@ -0,0 +1,321 @@
+<?php
+
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Route;
+
+use App\Http\Controllers\WbwTemplateController;
+use App\Http\Controllers\DhammaTermController;
+use App\Http\Controllers\SentenceController;
+use App\Http\Controllers\ProgressChapterController;
+use App\Http\Controllers\SentenceInfoController;
+use App\Http\Controllers\SentPrController;
+use App\Http\Controllers\TagController;
+use App\Http\Controllers\ViewController;
+use App\Http\Controllers\LikeController;
+use App\Http\Controllers\SentHistoryController;
+use App\Http\Controllers\PaliTextController;
+use App\Http\Controllers\ChannelController;
+use App\Http\Controllers\UserDictController;
+use App\Http\Controllers\CollectionController;
+use App\Http\Controllers\DictController;
+use App\Http\Controllers\AuthController;
+use App\Http\Controllers\ArticleController;
+use App\Http\Controllers\GroupController;
+use App\Http\Controllers\CorpusController;
+use App\Http\Controllers\ArticleProgressController;
+use App\Http\Controllers\ExportWbwController;
+use App\Http\Controllers\WbwLookupController;
+use App\Http\Controllers\UploadController;
+use App\Http\Controllers\DiscussionController;
+use App\Http\Controllers\UserController;
+use App\Http\Controllers\GroupMemberController;
+use App\Http\Controllers\ShareController;
+use App\Http\Controllers\CourseController;
+use App\Http\Controllers\CourseMemberController;
+use App\Http\Controllers\ExerciseController;
+use App\Http\Controllers\ArticleMapController;
+use App\Http\Controllers\VocabularyController;
+use App\Http\Controllers\CaseController;
+use App\Http\Controllers\DictMeaningController;
+use App\Http\Controllers\UserOperationDailyController;
+use App\Http\Controllers\UserStatisticController;
+use App\Http\Controllers\SentSimController;
+use App\Http\Controllers\NissayaEndingController;
+use App\Http\Controllers\RelationController;
+use App\Http\Controllers\TermVocabularyController;
+use App\Http\Controllers\RelatedParagraphController;
+use App\Http\Controllers\SearchController;
+use App\Http\Controllers\WordIndexController;
+use App\Http\Controllers\StudioController;
+use App\Http\Controllers\GrammarGuideController;
+use App\Http\Controllers\WbwController;
+use App\Http\Controllers\AttachmentController;
+use App\Http\Controllers\ApiController;
+use App\Http\Controllers\ProgressImgController;
+use App\Http\Controllers\RecentController;
+use App\Http\Controllers\MilestoneController;
+use App\Http\Controllers\ArticleNavController;
+use App\Http\Controllers\InviteController;
+use App\Http\Controllers\SignUpController;
+use App\Http\Controllers\TermSummaryController;
+use App\Http\Controllers\NissayaCardController;
+use App\Http\Controllers\SentInChannelController;
+use App\Http\Controllers\ChannelIOController;
+use App\Http\Controllers\ChapterIOController;
+use App\Http\Controllers\SentenceIOController;
+use App\Http\Controllers\WebHookController;
+use App\Http\Controllers\DictStatisticController;
+use App\Http\Controllers\SearchTitleController;
+use App\Http\Controllers\TransferController;
+use App\Http\Controllers\HealthCheckController;
+use App\Http\Controllers\OfflineIndexController;
+use App\Http\Controllers\TaskController;
+use App\Http\Controllers\ExportController;
+use App\Http\Controllers\DictVocabularyController;
+use App\Http\Controllers\DictInfoController;
+use App\Http\Controllers\PgPaliDictDownloadController;
+use App\Http\Controllers\SearchPaliDataController;
+use App\Http\Controllers\SearchPaliWbwController;
+use App\Http\Controllers\SearchPageNumberController;
+use App\Http\Controllers\NavPageController;
+use App\Http\Controllers\BookTitleController;
+use App\Http\Controllers\SystemTermController;
+use App\Http\Controllers\TermExportController;
+use App\Http\Controllers\NavArticleController;
+use App\Http\Controllers\NavCSParaController;
+use App\Http\Controllers\SentencesInChapterController;
+use App\Http\Controllers\CompoundController;
+use App\Http\Controllers\NotificationController;
+use App\Http\Controllers\InteractiveController;
+use App\Http\Controllers\ChapterIndexController;
+use App\Http\Controllers\WbwSentenceController;
+use App\Http\Controllers\SnowFlakeIdController;
+use App\Http\Controllers\ForgotPasswordController;
+use App\Http\Controllers\ResetPasswordController;
+use App\Http\Controllers\DiscussionCountController;
+use App\Http\Controllers\TagsInChapterCountController;
+use App\Http\Controllers\TagMapController;
+use App\Http\Controllers\EditableSentenceController;
+use App\Http\Controllers\ArticleFtsController;
+use App\Http\Controllers\NissayaCoverController;
+use App\Http\Controllers\AiTranslateController;
+use App\Http\Controllers\DictPreferenceController;
+use App\Http\Controllers\CommandController;
+use App\Http\Controllers\UserMilestoneController;
+use App\Http\Controllers\ProjectController;
+use App\Http\Controllers\TaskStatusController;
+use App\Http\Controllers\TaskGroupController;
+use App\Http\Controllers\ChapterController;
+use App\Http\Controllers\ProjectTreeController;
+use App\Http\Controllers\SiteInfoController;
+use App\Http\Controllers\PaliBookCategoryController;
+use App\Http\Controllers\AccessTokenController;
+use App\Http\Controllers\SearchWordSliceController;
+use App\Http\Controllers\AiModelController;
+use App\Http\Controllers\AiAssistantController;
+use App\Http\Controllers\ModelLogController;
+use App\Http\Controllers\SentenceAttachmentController;
+use App\Http\Controllers\EmailCertificationController;
+use App\Http\Controllers\MockOpenAIController;
+use App\Http\Controllers\SysModelController;
+use App\Http\Controllers\ChatController;
+use App\Http\Controllers\ChatMessageController;
+use App\Http\Controllers\SearchPlusController;
+use App\Http\Controllers\SearchSuggestController;
+use App\Http\Controllers\UpgradeController;
+use App\Http\Controllers\ChapterContentController;
+use App\Http\Controllers\ParagraphContentController;
+
+
+
+/*
+|--------------------------------------------------------------------------
+| API Routes
+|--------------------------------------------------------------------------
+|
+| Here is where you can register API routes for your application. These
+| routes are loaded by the RouteServiceProvider within a group which
+| is assigned the "api" middleware group. Enjoy building your API!
+|
+*/
+
+Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
+    return $request->user();
+});
+
+Route::get('/api/sentence/progress/image', [SentenceInfoController::class, 'showprogress']);
+Route::get('/api/sentence/progress/daily/image', [SentenceInfoController::class, 'showprogressdaily']);
+
+
+Route::group(['prefix' => 'v2'], function () {
+    Route::apiResource('wbw_templates', WbwTemplateController::class);
+
+    Route::apiResource('terms', DhammaTermController::class);
+    Route::apiResource('terms-export', TermExportController::class);
+    Route::get('terms-import', [TermExportController::class, 'import']);
+    Route::get('system-term/{lang}/{word}', [SystemTermController::class, "show"]);
+
+    Route::apiResource('sentence', SentenceController::class);
+    Route::apiResource('sent-in-channel', SentInChannelController::class);
+    Route::apiResource('sentpr', SentPrController::class);
+    Route::post('sent-pr-tree', [SentPrController::class, "pr_tree"]);
+    Route::apiResource('progress', ProgressChapterController::class);
+    Route::apiResource('tag', TagController::class);
+    Route::apiResource('view', ViewController::class);
+
+    Route::delete('like', [LikeController::class, 'delete']);
+    Route::apiResource('like', LikeController::class);
+    Route::apiResource('sent_history', SentHistoryController::class);
+    Route::get('sent_history_contribution', [SentHistoryController::class, 'contribution']);
+    Route::apiResource('palitext', PaliTextController::class);
+    Route::apiResource('channel', ChannelController::class);
+    Route::patch('channel', [ChannelController::class, "patch"]);
+    Route::get('channel-name/{name}', [ChannelController::class, "showByName"]);
+    Route::get('channel-my-number', [ChannelController::class, 'showMyNumber']);
+    Route::post('channel-progress', [ChannelController::class, "progress"]);
+    Route::delete('userdict', [UserDictController::class, 'delete']);
+    Route::apiResource('userdict', UserDictController::class);
+
+    Route::apiResource('anthology', CollectionController::class);
+    Route::get('anthology-my-number', [CollectionController::class, 'showMyNumber']);
+    Route::apiResource('dict', DictController::class);
+    Route::apiResource('article', ArticleController::class);
+    Route::get('article-my-number', [ArticleController::class, 'showMyNumber']);
+    Route::put('article-preview/{id}', [ArticleController::class, 'preview']);
+
+    Route::apiResource('group', GroupController::class);
+    Route::get('group-my-number', [GroupController::class, 'showMyNumber']);
+
+    Route::get('auth/current', [AuthController::class, 'getUserInfoByToken']);
+    Route::post('sign-in', [AuthController::class, 'signIn']);
+    Route::apiResource('auth/forgot-password', ForgotPasswordController::class);
+    Route::apiResource('auth/reset-password', ResetPasswordController::class);
+
+    Route::apiResource('corpus', CorpusController::class);
+    Route::get('corpus-sent/{id}', [CorpusController::class, 'showSent']);
+    Route::get('corpus-chapter/{id}', [CorpusController::class, 'showChapter']);
+    Route::get('corpus-sentences/{type}/{id}', [CorpusController::class, 'showSentences']);
+
+    Route::apiResource('article-progress', ArticleProgressController::class);
+
+    Route::post('export_wbw', [ExportWbwController::class, 'index']);
+    Route::apiResource('attachments', UploadController::class);
+    Route::apiResource('discussion', DiscussionController::class);
+    Route::post('sent-discussion-tree', [DiscussionController::class, "discussion_tree"]);
+    Route::get('discussion-anchor/{id}', [DiscussionController::class, 'anchor']);
+    Route::apiResource('user', UserController::class);
+    Route::apiResource('group-member', GroupMemberController::class);
+    Route::apiResource('share', ShareController::class);
+    Route::apiResource('wbwlookup', WbwLookupController::class);
+    Route::apiResource('course', CourseController::class);
+    Route::apiResource('course-member', CourseMemberController::class);
+    Route::put('course-member_set-channel', [CourseMemberController::class, 'set_channel']);
+    Route::get('course-my-course', [CourseController::class, 'showMyCourseNumber']);
+    Route::get('course-curr', [CourseMemberController::class, 'curr']);
+    Route::get('course-member-export', [CourseMemberController::class, "export"]);
+
+    Route::apiResource('exercise', ExerciseController::class);
+    Route::apiResource('article-map', ArticleMapController::class);
+    Route::apiResource('vocabulary', VocabularyController::class);
+    Route::apiResource('case', CaseController::class);
+    Route::apiResource('dict-meaning', DictMeaningController::class);
+    Route::apiResource('user-operation-daily', UserOperationDailyController::class);
+    Route::apiResource('user-statistic', UserStatisticController::class);
+    Route::apiResource('sent-sim', SentSimController::class);
+    Route::apiResource('nissaya-ending', NissayaEndingController::class);
+    Route::get('nissaya-ending-export', [NissayaEndingController::class, "export"]);
+    Route::get('nissaya-ending-import', [NissayaEndingController::class, "import"]);
+    Route::get('nissaya-ending-vocabulary', [NissayaEndingController::class, "vocabulary"]);
+    Route::apiResource('nissaya-card', NissayaCardController::class);
+    Route::apiResource('relation', RelationController::class);
+    Route::get('relation-export', [RelationController::class, "export"]);
+    Route::get('relation-import', [RelationController::class, "import"]);
+    Route::apiResource('term-vocabulary', TermVocabularyController::class);
+    Route::apiResource('related-paragraph', RelatedParagraphController::class);
+    Route::apiResource('search', SearchController::class);
+    Route::get('search-book-list', [SearchController::class, 'book_list']);
+    Route::apiResource('pali-word-index', WordIndexController::class);
+    Route::apiResource('studio', StudioController::class);
+    Route::apiResource('grammar-guide', GrammarGuideController::class);
+    Route::apiResource('wbw', WbwController::class);
+    Route::apiResource('attachment', AttachmentController::class);
+    Route::apiResource('api', ApiController::class);
+    Route::apiResource('progress-img', ProgressImgController::class);
+    Route::apiResource('recent', RecentController::class);
+    Route::apiResource('milestone', MilestoneController::class);
+    Route::apiResource('article-nav', ArticleNavController::class);
+    Route::apiResource('invite', InviteController::class);
+    Route::apiResource('sign-up', SignUpController::class);
+    Route::apiResource('term-summary', TermSummaryController::class);
+
+    Route::apiResource('channel-io', ChannelIOController::class);
+    Route::apiResource('chapter-io', ChapterIOController::class);
+    Route::apiResource('sentence-io', SentenceIOController::class);
+    Route::apiResource('webhook', WebHookController::class);
+    Route::apiResource('dict-statistic', DictStatisticController::class);
+    Route::apiResource('search-title-index', SearchTitleController::class);
+    Route::apiResource('transfer', TransferController::class);
+    Route::apiResource('health-check', HealthCheckController::class);
+    Route::apiResource('offline-index', OfflineIndexController::class);
+    Route::apiResource('task', TaskController::class);
+    Route::apiResource('export', ExportController::class);
+    Route::apiResource('dict-vocabulary', DictVocabularyController::class);
+    Route::apiResource('dict-info', DictInfoController::class);
+    Route::apiResource('pg-pali-dict-download', PgPaliDictDownloadController::class);
+    Route::apiResource('pali-search-data', SearchPaliDataController::class);
+    Route::apiResource('search-pali-wbw', SearchPaliWbwController::class);
+    Route::get('search-pali-wbw-books', [SearchPaliWbwController::class, 'book_list']);
+    Route::apiResource('search-page-number', SearchPageNumberController::class);
+    Route::apiResource('nav-page', NavPageController::class);
+    Route::apiResource('nav-article', NavArticleController::class);
+    Route::apiResource('nav-cs-para', NavCSParaController::class);
+    Route::apiResource('book-title', BookTitleController::class);
+    Route::apiResource('sentences-in-chapter', SentencesInChapterController::class);
+    Route::apiResource('compound', CompoundController::class);
+    Route::apiResource('notification', NotificationController::class);
+    Route::apiResource('interactive', InteractiveController::class);
+    Route::apiResource('chapter-index', ChapterIndexController::class);
+    Route::apiResource('wbw-sentence', WbwSentenceController::class);
+    Route::apiResource('snowflake', SnowFlakeIdController::class);
+    Route::apiResource('discussion-count', DiscussionCountController::class);
+    Route::apiResource('tags-in-chapter', TagsInChapterCountController::class);
+    Route::apiResource('tag-map', TagMapController::class);
+    Route::apiResource('editable-sentence', EditableSentenceController::class);
+    Route::apiResource('article-fts', ArticleFtsController::class);
+    Route::apiResource('nissaya-cover', NissayaCoverController::class);
+    Route::apiResource('ai-translate', AiTranslateController::class);
+    Route::apiResource('dict-preference', DictPreferenceController::class);
+    Route::apiResource('command', CommandController::class);
+    Route::apiResource('user-milestone', UserMilestoneController::class);
+    Route::apiResource('project', ProjectController::class);
+    Route::apiResource('task-status', TaskStatusController::class);
+    Route::apiResource('task-group', TaskGroupController::class);
+    Route::apiResource('chapter', ChapterController::class);
+    Route::apiResource('project-tree', ProjectTreeController::class);
+    Route::apiResource('site-info', SiteInfoController::class);
+    Route::apiResource('pali-book-category', PaliBookCategoryController::class);
+    Route::apiResource('access-token', AccessTokenController::class);
+    Route::apiResource('search-word-slice', SearchWordSliceController::class);
+    Route::apiResource('ai-model', AiModelController::class);
+    Route::apiResource('ai-assistant', AiAssistantController::class);
+    Route::apiResource('model-log', ModelLogController::class);
+    Route::apiResource('sentence-attachment', SentenceAttachmentController::class);
+    Route::apiResource('email-certification', EmailCertificationController::class);
+    Route::apiResource('sentence-info', SentenceInfoController::class);
+    Route::apiResource('system-model', SysModelController::class);
+    Route::apiResource('chats', ChatController::class);
+    Route::apiResource('chat-messages', ChatMessageController::class);
+    Route::apiResource('chapter-content', ChapterContentController::class);
+    Route::apiResource('paragraph-content', ParagraphContentController::class);
+
+    Route::post('mock/openai/chat/completions', [MockOpenAIController::class, 'chatCompletions']);
+    Route::post('mock/openai/completions', [MockOpenAIController::class, 'completions']);
+    Route::get('mock/openai/models', [MockOpenAIController::class, 'models']);
+});
+
+
+Route::group(['prefix' => 'v3'], function () {
+    Route::apiResource('search', SearchPlusController::class);
+    Route::apiResource('search-suggest', SearchSuggestController::class);
+    Route::apiResource('upgrade', UpgradeController::class);
+});

+ 108 - 1
api-v13/routes/web.php

@@ -1,5 +1,112 @@
 <?php
 
 use Illuminate\Support\Facades\Route;
+use Illuminate\Support\Facades\File;
+use App\Http\Controllers\WbwAnalysisController;
+use App\Http\Controllers\PageIndexController;
+use App\Http\Controllers\AssetsController;
+use App\Http\Controllers\BlogController;
+use App\Http\Controllers\DownloadController;
+use App\Http\Controllers\Library\AnthologyController;
+use App\Http\Controllers\Library\AnthologyReadController;
+use App\Http\Controllers\Library\BookController;
+use App\Http\Controllers\Library\WikiController;
+use App\Http\Controllers\Library\SearchController;
+use App\Http\Controllers\Library\HomeController;
+use App\Http\Controllers\Library\TipitakaController;
 
-Route::inertia('/', 'welcome')->name('home');
+/*
+|--------------------------------------------------------------------------
+| Web Routes
+|--------------------------------------------------------------------------
+|
+| Here is where you can register web routes for your application. These
+| routes are loaded by the RouteServiceProvider within a group which
+| contains the "web" middleware group. Now create something great!
+|
+*/
+
+Route::redirect('/app', '/app/pcdl/index.php');
+Route::redirect('/app/pcdl', '/app/pcdl/index.php');
+
+Route::get('/', [PageIndexController::class, 'index']);
+
+Route::get('/wbwanalyses', [WbwAnalysisController::class, 'index']);
+Route::get('/attachments/{bucket}/{name}', [AssetsController::class, 'show']);
+
+Route::get('/export/wbw', function () {
+    return view('export_wbw', ['sentences' => []]);
+});
+
+
+Route::get('/privacy/{file}', function (string $file) {
+    $path = base_path("documents/mobile/privacy/{$file}.md");
+
+    abort_unless(File::exists($path), 404);
+
+    return view('privacy', [
+        'content' => File::get($path),
+    ]);
+});
+
+Route::get('/book/{id}', function ($id) {
+    return view('book', ['id' => $id]);
+});
+Route::redirect('/privacy', '/privacy/index');
+
+
+
+
+Route::post('/theme/toggle', [BookController::class, 'toggleTheme'])->name('theme.toggle');
+Route::post('/logout', function () {
+    // Handle logout
+    //Auth::logout();
+    return redirect('/login');
+})->name('logout');
+
+Route::prefix('library')->name('library.')->group(function () {
+    Route::get('/', [HomeController::class, 'index'])->name('home');
+
+    Route::get('/tipitaka', [TipitakaController::class, 'index'])->name('tipitaka.index');
+    Route::get('/tipitaka/category/{id}', [TipitakaController::class, 'index'])->name('tipitaka.category');
+    Route::get('/tipitaka/{id}', [BookController::class, 'show'])->name('tipitaka.show');
+    Route::get('/tipitaka/{id}/read', [BookController::class, 'read'])->name('tipitaka.read');
+
+    Route::get('/wiki', [WikiController::class, 'home'])->name('wiki.home');
+    Route::get('/wiki/{lang}', [WikiController::class, 'index'])->name('wiki.index');
+    Route::get('/wiki/{lang}/{word}', [WikiController::class, 'show'])->name('wiki.show');
+
+    Route::get('/course', [DownloadController::class, 'index'])->name('course');
+    Route::get('/download', [DownloadController::class, 'index'])->name('download');
+    // 文集
+    Route::get('/anthology',          [AnthologyController::class, 'index'])->name('anthology.index');
+    Route::get('/anthology/{id}',     [AnthologyController::class, 'show'])->name('anthology.show');
+    Route::get(
+        '/anthology/{anthology}/read/{article}',
+        [AnthologyReadController::class, 'read']
+    )->name('anthology.read');
+
+    Route::get('/search', [SearchController::class, 'search'])->name('search');
+});
+// 博客路由
+Route::prefix('blog')->group(function () {
+    Route::get('/{user}', [BlogController::class, 'index'])->name('blog.index')->where('user', '[a-zA-Z0-9_-]+');
+    Route::get('/{user}/categories', [BlogController::class, 'categories'])->name('blog.categories');
+    Route::get('/{user}/category/{category1}/{category2?}/{category3?}/{category4?}/{category5?}', [BlogController::class, 'category'])->name('blog.category');
+    Route::get('/{user}/archives', [BlogController::class, 'archives'])->name('blog.archives');
+    Route::get('/{user}/archives/{year}', [BlogController::class, 'archivesByYear'])->name('blog.archives.year');
+    Route::get('/{user}/tag/{tag}', [BlogController::class, 'tag'])->name('blog.tag');
+    Route::get('/{user}/search', [BlogController::class, 'search'])->name('blog.search');
+    Route::get('/{user}/{post}', [BlogController::class, 'show'])
+        ->name('blog.show')
+        ->where([
+            'user' => '[a-zA-Z0-9_-]+',
+            'post' => '[a-zA-Z0-9_-]+',
+        ]);
+});
+
+Route::group(['prefix' => 'tools'], function () {
+    Route::get('/nissaya_format_converter', function () {
+        return view('nissaya_format_converter');
+    });
+});