Compare commits
265 Commits
#MSG01/cha
...
master
@ -0,0 +1,62 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="FacetManager">
|
||||||
|
<facet type="android" name="Android">
|
||||||
|
<configuration />
|
||||||
|
</facet>
|
||||||
|
</component>
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/geolocator_apple/example/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/geolocator_apple/example/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/geolocator_apple/example/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/fluttertoast/example/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/fluttertoast/example/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/fluttertoast/example/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_inappwebview/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_inappwebview/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_inappwebview/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_inappwebview/example/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_inappwebview/example/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_inappwebview/example/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_native_splash/example/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_native_splash/example/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_native_splash/example/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/geolocator_apple/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/geolocator_apple/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/geolocator_apple/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/home_indicator/example/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/home_indicator/example/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/home_indicator/example/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/path_provider_ios/example/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/path_provider_ios/example/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/path_provider_ios/example/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/vibration/example/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/vibration/example/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/vibration/example/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/path_provider_ios/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/path_provider_ios/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/path_provider_ios/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/vibration/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/vibration/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/vibration/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_native_splash/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_native_splash/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/flutter_native_splash/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/fluttertoast/.dart_tool" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/fluttertoast/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/fluttertoast/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/home_indicator/build" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/home_indicator/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/Sources/dafl_project_flutter/ios/.symlinks/plugins/home_indicator/.dart_tool" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="jdk" jdkName="Android API 33, extension level 3 Platform" jdkType="Android SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||||
|
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||||
|
</component>
|
||||||
|
</module>
|
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="dataSourceStorageLocal" created-in="PS-222.4345.15">
|
||||||
|
<data-source name="@localhost" uuid="f334e98a-3c30-4412-8c71-35fe124ed605">
|
||||||
|
<database-info product="" version="" jdbc-version="" driver-name="" driver-version="" dbms="MARIADB" exact-version="0" />
|
||||||
|
<secret-storage>forget</secret-storage>
|
||||||
|
<schema-mapping />
|
||||||
|
</data-source>
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||||
|
<data-source source="LOCAL" name="@localhost" uuid="f334e98a-3c30-4412-8c71-35fe124ed605">
|
||||||
|
<driver-ref>mariadb</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.mariadb.jdbc.Driver</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:mariadb://localhost:3306</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<dataSource name="@localhost">
|
||||||
|
<database-model serializer="dbm" dbms="MARIADB" family-id="MARIADB" format-version="4.43">
|
||||||
|
<root id="1"/>
|
||||||
|
<schema id="2" parent="1" name="information_schema"/>
|
||||||
|
<schema id="3" parent="1" name="mysql"/>
|
||||||
|
<schema id="4" parent="1" name="performance_schema"/>
|
||||||
|
<schema id="5" parent="1" name="phpmyadmin"/>
|
||||||
|
<schema id="6" parent="1" name="positiondaflmusic"/>
|
||||||
|
<schema id="7" parent="1" name="projetphp"/>
|
||||||
|
<schema id="8" parent="1" name="test"/>
|
||||||
|
</database-model>
|
||||||
|
</dataSource>
|
@ -0,0 +1,2 @@
|
|||||||
|
#n:information_schema
|
||||||
|
!<md> [null, 0, null, null, -2147483648, -2147483648]
|
@ -0,0 +1,2 @@
|
|||||||
|
#n:mysql
|
||||||
|
!<md> [null, 0, null, null, -2147483648, -2147483648]
|
@ -0,0 +1,2 @@
|
|||||||
|
#n:performance_schema
|
||||||
|
!<md> [null, 0, null, null, -2147483648, -2147483648]
|
@ -0,0 +1,417 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DBNavigator.Project.DataEditorManager">
|
||||||
|
<record-view-column-sorting-type value="BY_INDEX" />
|
||||||
|
<value-preview-text-wrapping value="true" />
|
||||||
|
<value-preview-pinned value="false" />
|
||||||
|
</component>
|
||||||
|
<component name="DBNavigator.Project.DatabaseFileManager">
|
||||||
|
<open-files />
|
||||||
|
</component>
|
||||||
|
<component name="DBNavigator.Project.EditorStateManager">
|
||||||
|
<last-used-providers />
|
||||||
|
</component>
|
||||||
|
<component name="DBNavigator.Project.Settings">
|
||||||
|
<connections />
|
||||||
|
<browser-settings>
|
||||||
|
<general>
|
||||||
|
<display-mode value="TABBED" />
|
||||||
|
<navigation-history-size value="100" />
|
||||||
|
<show-object-details value="false" />
|
||||||
|
</general>
|
||||||
|
<filters>
|
||||||
|
<object-type-filter>
|
||||||
|
<object-type name="SCHEMA" enabled="true" />
|
||||||
|
<object-type name="USER" enabled="true" />
|
||||||
|
<object-type name="ROLE" enabled="true" />
|
||||||
|
<object-type name="PRIVILEGE" enabled="true" />
|
||||||
|
<object-type name="CHARSET" enabled="true" />
|
||||||
|
<object-type name="TABLE" enabled="true" />
|
||||||
|
<object-type name="VIEW" enabled="true" />
|
||||||
|
<object-type name="MATERIALIZED_VIEW" enabled="true" />
|
||||||
|
<object-type name="NESTED_TABLE" enabled="true" />
|
||||||
|
<object-type name="COLUMN" enabled="true" />
|
||||||
|
<object-type name="INDEX" enabled="true" />
|
||||||
|
<object-type name="CONSTRAINT" enabled="true" />
|
||||||
|
<object-type name="DATASET_TRIGGER" enabled="true" />
|
||||||
|
<object-type name="DATABASE_TRIGGER" enabled="true" />
|
||||||
|
<object-type name="SYNONYM" enabled="true" />
|
||||||
|
<object-type name="SEQUENCE" enabled="true" />
|
||||||
|
<object-type name="PROCEDURE" enabled="true" />
|
||||||
|
<object-type name="FUNCTION" enabled="true" />
|
||||||
|
<object-type name="PACKAGE" enabled="true" />
|
||||||
|
<object-type name="TYPE" enabled="true" />
|
||||||
|
<object-type name="TYPE_ATTRIBUTE" enabled="true" />
|
||||||
|
<object-type name="ARGUMENT" enabled="true" />
|
||||||
|
<object-type name="DIMENSION" enabled="true" />
|
||||||
|
<object-type name="CLUSTER" enabled="true" />
|
||||||
|
<object-type name="DBLINK" enabled="true" />
|
||||||
|
</object-type-filter>
|
||||||
|
</filters>
|
||||||
|
<sorting>
|
||||||
|
<object-type name="COLUMN" sorting-type="NAME" />
|
||||||
|
<object-type name="FUNCTION" sorting-type="NAME" />
|
||||||
|
<object-type name="PROCEDURE" sorting-type="NAME" />
|
||||||
|
<object-type name="ARGUMENT" sorting-type="POSITION" />
|
||||||
|
<object-type name="TYPE ATTRIBUTE" sorting-type="POSITION" />
|
||||||
|
</sorting>
|
||||||
|
<default-editors>
|
||||||
|
<object-type name="VIEW" editor-type="SELECTION" />
|
||||||
|
<object-type name="PACKAGE" editor-type="SELECTION" />
|
||||||
|
<object-type name="TYPE" editor-type="SELECTION" />
|
||||||
|
</default-editors>
|
||||||
|
</browser-settings>
|
||||||
|
<navigation-settings>
|
||||||
|
<lookup-filters>
|
||||||
|
<lookup-objects>
|
||||||
|
<object-type name="SCHEMA" enabled="true" />
|
||||||
|
<object-type name="USER" enabled="false" />
|
||||||
|
<object-type name="ROLE" enabled="false" />
|
||||||
|
<object-type name="PRIVILEGE" enabled="false" />
|
||||||
|
<object-type name="CHARSET" enabled="false" />
|
||||||
|
<object-type name="TABLE" enabled="true" />
|
||||||
|
<object-type name="VIEW" enabled="true" />
|
||||||
|
<object-type name="MATERIALIZED VIEW" enabled="true" />
|
||||||
|
<object-type name="INDEX" enabled="true" />
|
||||||
|
<object-type name="CONSTRAINT" enabled="true" />
|
||||||
|
<object-type name="DATASET TRIGGER" enabled="true" />
|
||||||
|
<object-type name="DATABASE TRIGGER" enabled="true" />
|
||||||
|
<object-type name="SYNONYM" enabled="false" />
|
||||||
|
<object-type name="SEQUENCE" enabled="true" />
|
||||||
|
<object-type name="PROCEDURE" enabled="true" />
|
||||||
|
<object-type name="FUNCTION" enabled="true" />
|
||||||
|
<object-type name="PACKAGE" enabled="true" />
|
||||||
|
<object-type name="TYPE" enabled="true" />
|
||||||
|
<object-type name="DIMENSION" enabled="false" />
|
||||||
|
<object-type name="CLUSTER" enabled="false" />
|
||||||
|
<object-type name="DBLINK" enabled="true" />
|
||||||
|
</lookup-objects>
|
||||||
|
<force-database-load value="false" />
|
||||||
|
<prompt-connection-selection value="true" />
|
||||||
|
<prompt-schema-selection value="true" />
|
||||||
|
</lookup-filters>
|
||||||
|
</navigation-settings>
|
||||||
|
<dataset-grid-settings>
|
||||||
|
<general>
|
||||||
|
<enable-zooming value="true" />
|
||||||
|
<enable-column-tooltip value="true" />
|
||||||
|
</general>
|
||||||
|
<sorting>
|
||||||
|
<nulls-first value="true" />
|
||||||
|
<max-sorting-columns value="4" />
|
||||||
|
</sorting>
|
||||||
|
<audit-columns>
|
||||||
|
<column-names value="" />
|
||||||
|
<visible value="true" />
|
||||||
|
<editable value="false" />
|
||||||
|
</audit-columns>
|
||||||
|
</dataset-grid-settings>
|
||||||
|
<dataset-editor-settings>
|
||||||
|
<text-editor-popup>
|
||||||
|
<active value="false" />
|
||||||
|
<active-if-empty value="false" />
|
||||||
|
<data-length-threshold value="100" />
|
||||||
|
<popup-delay value="1000" />
|
||||||
|
</text-editor-popup>
|
||||||
|
<values-actions-popup>
|
||||||
|
<show-popup-button value="true" />
|
||||||
|
<element-count-threshold value="1000" />
|
||||||
|
<data-length-threshold value="250" />
|
||||||
|
</values-actions-popup>
|
||||||
|
<general>
|
||||||
|
<fetch-block-size value="100" />
|
||||||
|
<fetch-timeout value="30" />
|
||||||
|
<trim-whitespaces value="true" />
|
||||||
|
<convert-empty-strings-to-null value="true" />
|
||||||
|
<select-content-on-cell-edit value="true" />
|
||||||
|
<large-value-preview-active value="true" />
|
||||||
|
</general>
|
||||||
|
<filters>
|
||||||
|
<prompt-filter-dialog value="true" />
|
||||||
|
<default-filter-type value="BASIC" />
|
||||||
|
</filters>
|
||||||
|
<qualified-text-editor text-length-threshold="300">
|
||||||
|
<content-types>
|
||||||
|
<content-type name="Text" enabled="true" />
|
||||||
|
<content-type name="Properties" enabled="true" />
|
||||||
|
<content-type name="XML" enabled="true" />
|
||||||
|
<content-type name="DTD" enabled="true" />
|
||||||
|
<content-type name="HTML" enabled="true" />
|
||||||
|
<content-type name="XHTML" enabled="true" />
|
||||||
|
<content-type name="Java" enabled="true" />
|
||||||
|
<content-type name="SQL" enabled="true" />
|
||||||
|
<content-type name="PL/SQL" enabled="true" />
|
||||||
|
<content-type name="JSON" enabled="true" />
|
||||||
|
<content-type name="JSON5" enabled="true" />
|
||||||
|
<content-type name="Groovy" enabled="true" />
|
||||||
|
<content-type name="AIDL" enabled="true" />
|
||||||
|
<content-type name="YAML" enabled="true" />
|
||||||
|
<content-type name="Manifest" enabled="true" />
|
||||||
|
</content-types>
|
||||||
|
</qualified-text-editor>
|
||||||
|
<record-navigation>
|
||||||
|
<navigation-target value="VIEWER" />
|
||||||
|
</record-navigation>
|
||||||
|
</dataset-editor-settings>
|
||||||
|
<code-editor-settings>
|
||||||
|
<general>
|
||||||
|
<show-object-navigation-gutter value="false" />
|
||||||
|
<show-spec-declaration-navigation-gutter value="true" />
|
||||||
|
<enable-spellchecking value="true" />
|
||||||
|
<enable-reference-spellchecking value="false" />
|
||||||
|
</general>
|
||||||
|
<confirmations>
|
||||||
|
<save-changes value="false" />
|
||||||
|
<revert-changes value="true" />
|
||||||
|
</confirmations>
|
||||||
|
</code-editor-settings>
|
||||||
|
<code-completion-settings>
|
||||||
|
<filters>
|
||||||
|
<basic-filter>
|
||||||
|
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
|
||||||
|
<filter-element type="RESERVED_WORD" id="function" selected="true" />
|
||||||
|
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
|
||||||
|
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
|
||||||
|
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="schema" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="role" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="user" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="privilege" selected="true" />
|
||||||
|
<user-schema>
|
||||||
|
<filter-element type="OBJECT" id="table" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="view" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="index" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="synonym" selected="false" />
|
||||||
|
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="function" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="package" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="type" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||||
|
</user-schema>
|
||||||
|
<public-schema>
|
||||||
|
<filter-element type="OBJECT" id="table" selected="false" />
|
||||||
|
<filter-element type="OBJECT" id="view" selected="false" />
|
||||||
|
<filter-element type="OBJECT" id="materialized view" selected="false" />
|
||||||
|
<filter-element type="OBJECT" id="index" selected="false" />
|
||||||
|
<filter-element type="OBJECT" id="constraint" selected="false" />
|
||||||
|
<filter-element type="OBJECT" id="trigger" selected="false" />
|
||||||
|
<filter-element type="OBJECT" id="synonym" selected="false" />
|
||||||
|
<filter-element type="OBJECT" id="sequence" selected="false" />
|
||||||
|
<filter-element type="OBJECT" id="procedure" selected="false" />
|
||||||
|
<filter-element type="OBJECT" id="function" selected="false" />
|
||||||
|
<filter-element type="OBJECT" id="package" selected="false" />
|
||||||
|
<filter-element type="OBJECT" id="type" selected="false" />
|
||||||
|
<filter-element type="OBJECT" id="dimension" selected="false" />
|
||||||
|
<filter-element type="OBJECT" id="cluster" selected="false" />
|
||||||
|
<filter-element type="OBJECT" id="dblink" selected="false" />
|
||||||
|
</public-schema>
|
||||||
|
<any-schema>
|
||||||
|
<filter-element type="OBJECT" id="table" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="view" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="index" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="synonym" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="function" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="package" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="type" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||||
|
</any-schema>
|
||||||
|
</basic-filter>
|
||||||
|
<extended-filter>
|
||||||
|
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
|
||||||
|
<filter-element type="RESERVED_WORD" id="function" selected="true" />
|
||||||
|
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
|
||||||
|
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
|
||||||
|
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="schema" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="user" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="role" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="privilege" selected="true" />
|
||||||
|
<user-schema>
|
||||||
|
<filter-element type="OBJECT" id="table" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="view" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="index" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="synonym" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="function" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="package" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="type" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||||
|
</user-schema>
|
||||||
|
<public-schema>
|
||||||
|
<filter-element type="OBJECT" id="table" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="view" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="index" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="synonym" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="function" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="package" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="type" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||||
|
</public-schema>
|
||||||
|
<any-schema>
|
||||||
|
<filter-element type="OBJECT" id="table" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="view" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="materialized view" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="index" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="constraint" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="trigger" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="synonym" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="sequence" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="procedure" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="function" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="package" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="type" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="dimension" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="cluster" selected="true" />
|
||||||
|
<filter-element type="OBJECT" id="dblink" selected="true" />
|
||||||
|
</any-schema>
|
||||||
|
</extended-filter>
|
||||||
|
</filters>
|
||||||
|
<sorting enabled="true">
|
||||||
|
<sorting-element type="RESERVED_WORD" id="keyword" />
|
||||||
|
<sorting-element type="RESERVED_WORD" id="datatype" />
|
||||||
|
<sorting-element type="OBJECT" id="column" />
|
||||||
|
<sorting-element type="OBJECT" id="table" />
|
||||||
|
<sorting-element type="OBJECT" id="view" />
|
||||||
|
<sorting-element type="OBJECT" id="materialized view" />
|
||||||
|
<sorting-element type="OBJECT" id="index" />
|
||||||
|
<sorting-element type="OBJECT" id="constraint" />
|
||||||
|
<sorting-element type="OBJECT" id="trigger" />
|
||||||
|
<sorting-element type="OBJECT" id="synonym" />
|
||||||
|
<sorting-element type="OBJECT" id="sequence" />
|
||||||
|
<sorting-element type="OBJECT" id="procedure" />
|
||||||
|
<sorting-element type="OBJECT" id="function" />
|
||||||
|
<sorting-element type="OBJECT" id="package" />
|
||||||
|
<sorting-element type="OBJECT" id="type" />
|
||||||
|
<sorting-element type="OBJECT" id="dimension" />
|
||||||
|
<sorting-element type="OBJECT" id="cluster" />
|
||||||
|
<sorting-element type="OBJECT" id="dblink" />
|
||||||
|
<sorting-element type="OBJECT" id="schema" />
|
||||||
|
<sorting-element type="OBJECT" id="role" />
|
||||||
|
<sorting-element type="OBJECT" id="user" />
|
||||||
|
<sorting-element type="RESERVED_WORD" id="function" />
|
||||||
|
<sorting-element type="RESERVED_WORD" id="parameter" />
|
||||||
|
</sorting>
|
||||||
|
<format>
|
||||||
|
<enforce-code-style-case value="true" />
|
||||||
|
</format>
|
||||||
|
</code-completion-settings>
|
||||||
|
<execution-engine-settings>
|
||||||
|
<statement-execution>
|
||||||
|
<fetch-block-size value="100" />
|
||||||
|
<execution-timeout value="20" />
|
||||||
|
<debug-execution-timeout value="600" />
|
||||||
|
<focus-result value="false" />
|
||||||
|
<prompt-execution value="false" />
|
||||||
|
</statement-execution>
|
||||||
|
<script-execution>
|
||||||
|
<command-line-interfaces />
|
||||||
|
<execution-timeout value="300" />
|
||||||
|
</script-execution>
|
||||||
|
<method-execution>
|
||||||
|
<execution-timeout value="30" />
|
||||||
|
<debug-execution-timeout value="600" />
|
||||||
|
<parameter-history-size value="10" />
|
||||||
|
</method-execution>
|
||||||
|
</execution-engine-settings>
|
||||||
|
<operation-settings>
|
||||||
|
<transactions>
|
||||||
|
<uncommitted-changes>
|
||||||
|
<on-project-close value="ASK" />
|
||||||
|
<on-disconnect value="ASK" />
|
||||||
|
<on-autocommit-toggle value="ASK" />
|
||||||
|
</uncommitted-changes>
|
||||||
|
<multiple-uncommitted-changes>
|
||||||
|
<on-commit value="ASK" />
|
||||||
|
<on-rollback value="ASK" />
|
||||||
|
</multiple-uncommitted-changes>
|
||||||
|
</transactions>
|
||||||
|
<session-browser>
|
||||||
|
<disconnect-session value="ASK" />
|
||||||
|
<kill-session value="ASK" />
|
||||||
|
<reload-on-filter-change value="false" />
|
||||||
|
</session-browser>
|
||||||
|
<compiler>
|
||||||
|
<compile-type value="KEEP" />
|
||||||
|
<compile-dependencies value="ASK" />
|
||||||
|
<always-show-controls value="false" />
|
||||||
|
</compiler>
|
||||||
|
<debugger>
|
||||||
|
<debugger-type value="ASK" />
|
||||||
|
<use-generic-runners value="true" />
|
||||||
|
</debugger>
|
||||||
|
</operation-settings>
|
||||||
|
<ddl-file-settings>
|
||||||
|
<extensions>
|
||||||
|
<mapping file-type-id="VIEW" extensions="vw" />
|
||||||
|
<mapping file-type-id="TRIGGER" extensions="trg" />
|
||||||
|
<mapping file-type-id="PROCEDURE" extensions="prc" />
|
||||||
|
<mapping file-type-id="FUNCTION" extensions="fnc" />
|
||||||
|
<mapping file-type-id="PACKAGE" extensions="pkg" />
|
||||||
|
<mapping file-type-id="PACKAGE_SPEC" extensions="pks" />
|
||||||
|
<mapping file-type-id="PACKAGE_BODY" extensions="pkb" />
|
||||||
|
<mapping file-type-id="TYPE" extensions="tpe" />
|
||||||
|
<mapping file-type-id="TYPE_SPEC" extensions="tps" />
|
||||||
|
<mapping file-type-id="TYPE_BODY" extensions="tpb" />
|
||||||
|
</extensions>
|
||||||
|
<general>
|
||||||
|
<lookup-ddl-files value="true" />
|
||||||
|
<create-ddl-files value="false" />
|
||||||
|
<synchronize-ddl-files value="true" />
|
||||||
|
<use-qualified-names value="false" />
|
||||||
|
<make-scripts-rerunnable value="true" />
|
||||||
|
</general>
|
||||||
|
</ddl-file-settings>
|
||||||
|
<general-settings>
|
||||||
|
<regional-settings>
|
||||||
|
<date-format value="MEDIUM" />
|
||||||
|
<number-format value="UNGROUPED" />
|
||||||
|
<locale value="SYSTEM_DEFAULT" />
|
||||||
|
<use-custom-formats value="false" />
|
||||||
|
</regional-settings>
|
||||||
|
<environment>
|
||||||
|
<environment-types>
|
||||||
|
<environment-type id="development" name="Development" description="Development environment" color="-2430209/-12296320" readonly-code="false" readonly-data="false" />
|
||||||
|
<environment-type id="integration" name="Integration" description="Integration environment" color="-2621494/-12163514" readonly-code="true" readonly-data="false" />
|
||||||
|
<environment-type id="production" name="Production" description="Productive environment" color="-11574/-10271420" readonly-code="true" readonly-data="true" />
|
||||||
|
<environment-type id="other" name="Other" description="" color="-1576/-10724543" readonly-code="false" readonly-data="false" />
|
||||||
|
</environment-types>
|
||||||
|
<visibility-settings>
|
||||||
|
<connection-tabs value="true" />
|
||||||
|
<dialog-headers value="true" />
|
||||||
|
<object-editor-tabs value="true" />
|
||||||
|
<script-editor-tabs value="false" />
|
||||||
|
<execution-result-tabs value="true" />
|
||||||
|
</visibility-settings>
|
||||||
|
</environment>
|
||||||
|
</general-settings>
|
||||||
|
</component>
|
||||||
|
<component name="DBNavigator.Project.StatementExecutionManager">
|
||||||
|
<execution-variables />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="PhpProjectSharedConfiguration" php_language_level="8.1">
|
||||||
|
<option name="suggestChangeDefaultLanguageLevel" value="false" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="SqlDialectMappings">
|
||||||
|
<file url="file://$PROJECT_DIR$/Sources/php_script/script/insertAndMakeListUser.php" dialect="GenericSQL" />
|
||||||
|
<file url="file://$PROJECT_DIR$/Sources/php_script/script/test.php" dialect="GenericSQL" />
|
||||||
|
</component>
|
||||||
|
</project>
|
After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 135 KiB |
@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/symfony/translation" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/nesbot/carbon" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/pimple/pimple" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/psr/simple-cache" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/psr/http-message" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/illuminate/support" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/psr/container" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/doctrine/inflector" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/illuminate/contracts" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/slim/slim" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/illuminate/database" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/illuminate/container" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/nikic/fast-route" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/composer" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/symfony/polyfill-php80" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/kylekatarnls/update-helper" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/symfony/translation-contracts" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/sources/vendor/symfony/polyfill-mbstring" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/api_database.iml" filepath="$PROJECT_DIR$/.idea/api_database.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="PhpIncludePathManager">
|
||||||
|
<include_path>
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/symfony/translation" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/nesbot/carbon" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/pimple/pimple" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/psr/simple-cache" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/psr/http-message" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/illuminate/support" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/psr/container" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/doctrine/inflector" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/illuminate/contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/slim/slim" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/illuminate/database" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/illuminate/container" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/nikic/fast-route" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/composer" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/symfony/polyfill-php80" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/kylekatarnls/update-helper" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/symfony/translation-contracts" />
|
||||||
|
<path value="$PROJECT_DIR$/sources/vendor/symfony/polyfill-mbstring" />
|
||||||
|
</include_path>
|
||||||
|
</component>
|
||||||
|
<component name="PhpProjectSharedConfiguration" php_language_level="7.4">
|
||||||
|
<option name="suggestChangeDefaultLanguageLevel" value="false" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="SqlDialectMappings">
|
||||||
|
<file url="file://$PROJECT_DIR$/database/dafl_music.sql" dialect="MariaDB" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,61 @@
|
|||||||
|
-- phpMyAdmin SQL Dump
|
||||||
|
-- version 5.2.0
|
||||||
|
-- https://www.phpmyadmin.net/
|
||||||
|
--
|
||||||
|
-- Host: localhost
|
||||||
|
-- Generation Time: Dec 25, 2022 at 09:09 PM
|
||||||
|
-- Server version: 10.9.4-MariaDB
|
||||||
|
-- PHP Version: 8.1.13
|
||||||
|
|
||||||
|
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||||||
|
START TRANSACTION;
|
||||||
|
SET time_zone = "+00:00";
|
||||||
|
|
||||||
|
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT = @@CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS = @@CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET @OLD_COLLATION_CONNECTION = @@COLLATION_CONNECTION */;
|
||||||
|
/*!40101 SET NAMES utf8mb4 */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Database: `dafl_music`
|
||||||
|
--
|
||||||
|
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `users`
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE `users`
|
||||||
|
(
|
||||||
|
`idDafl` varchar(25) NOT NULL,
|
||||||
|
`idSpotify` varchar(25) NOT NULL,
|
||||||
|
`password` varchar(250) NOT NULL
|
||||||
|
) ENGINE = InnoDB
|
||||||
|
DEFAULT CHARSET = utf8mb4
|
||||||
|
COLLATE = utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `users`
|
||||||
|
--
|
||||||
|
|
||||||
|
INSERT INTO `users` (`idDafl`, `idSpotify`, `password`)
|
||||||
|
VALUES ('felix', 'idspotfelix', 'mdp'),
|
||||||
|
('lucas', 'spottest', 'pwdtest');
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Indexes for dumped tables
|
||||||
|
--
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Indexes for table `users`
|
||||||
|
--
|
||||||
|
ALTER TABLE `users`
|
||||||
|
ADD PRIMARY KEY (`idDafl`),
|
||||||
|
ADD UNIQUE KEY `idSpotify` (`idSpotify`);
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
/*!40101 SET CHARACTER_SET_CLIENT = @OLD_CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET CHARACTER_SET_RESULTS = @OLD_CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET COLLATION_CONNECTION = @OLD_COLLATION_CONNECTION */;
|
@ -0,0 +1 @@
|
|||||||
|
vendor/*
|
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Connection extends PDO
|
||||||
|
{
|
||||||
|
|
||||||
|
private $stmt;
|
||||||
|
|
||||||
|
public function __construct(string $dsn, string $username, string $password)
|
||||||
|
{
|
||||||
|
|
||||||
|
parent::__construct($dsn, $username, $password);
|
||||||
|
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** * @param string $query
|
||||||
|
* @param array $parameters *
|
||||||
|
* @return bool Returns `true` on success, `false` otherwise
|
||||||
|
*/
|
||||||
|
public function executeQuery(string $query, array $parameters = []): bool
|
||||||
|
{
|
||||||
|
$this->stmt = parent::prepare($query);
|
||||||
|
foreach ($parameters as $name => $value) {
|
||||||
|
$this->stmt->bindValue($name, $value[0], $value[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->stmt->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getResults(): array
|
||||||
|
{
|
||||||
|
return $this->stmt->fetchall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require "gateways/UserGateway.php";
|
||||||
|
require "gateways/LikesGateway.php";
|
||||||
|
require "business/User.php";
|
||||||
|
|
||||||
|
class Model
|
||||||
|
{
|
||||||
|
public function getInformationsUser($id): array
|
||||||
|
{
|
||||||
|
global $app;
|
||||||
|
$db = $app->getContainer()['settings']['db'];
|
||||||
|
$id = filter_var($id, FILTER_SANITIZE_STRING);
|
||||||
|
$gw = new UserGateway(new Connection($db['dsn'], $db['user'], $db['pass']));
|
||||||
|
$userDb = $gw->getInformations($id);
|
||||||
|
if (count($userDb) != 1) {
|
||||||
|
throw new Exception("no user matches id");
|
||||||
|
}
|
||||||
|
$user = new User($userDb[0][0], $userDb[0][1]);
|
||||||
|
return $user->getInformations();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addUser($idDafl, $idSpotify, $passw): void
|
||||||
|
{
|
||||||
|
global $app;
|
||||||
|
$db = $app->getContainer()['settings']['db'];
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
$data['idDafl'] = filter_var($idDafl, FILTER_SANITIZE_STRING);
|
||||||
|
$data['idSpotify'] = filter_var($idSpotify, FILTER_SANITIZE_STRING);
|
||||||
|
$data['passw'] = filter_var($passw, FILTER_SANITIZE_STRING);
|
||||||
|
$gw = new UserGateway(new Connection($db['dsn'], $db['user'], $db['pass']));
|
||||||
|
$gw->addUser($data['idDafl'], $data['idSpotify'], $data['passw']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function like($user,$liked) : bool {
|
||||||
|
global $app;
|
||||||
|
$db = $app->getContainer()['settings']['db'];
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
$data['user'] = filter_var($user, FILTER_SANITIZE_STRING);
|
||||||
|
$data['liked'] = filter_var($liked, FILTER_SANITIZE_STRING);
|
||||||
|
$gw = new LikesGateway(new Connection($db['dsn'], $db['user'], $db['pass']));
|
||||||
|
return $gw->addUser($data['idDafl'], $data['idSpotify'], $data['passw']);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class User
|
||||||
|
{
|
||||||
|
private string $idDafl;
|
||||||
|
private string $idSpotify;
|
||||||
|
|
||||||
|
public function __construct(string $idDafl, string $idSpotify)
|
||||||
|
{
|
||||||
|
$this->idDafl = $idDafl;
|
||||||
|
$this->idSpotify = $idSpotify;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getIdDafl(): string
|
||||||
|
{
|
||||||
|
return $this->idDafl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getIdSpotify(): string
|
||||||
|
{
|
||||||
|
return $this->idSpotify;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInformations(): array
|
||||||
|
{
|
||||||
|
return array($this->idDafl, $this->idSpotify);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$config['displayErrorDetails'] = true;
|
||||||
|
$config['addContentLengthHeader'] = false;
|
||||||
|
|
||||||
|
$config['db']['dsn'] = 'mysql:host=localhost;dbname=dafl_music';
|
||||||
|
$config['db']['user'] = 'root';
|
||||||
|
$config['db']['pass'] = 'root';
|
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class LikesGateway
|
||||||
|
{
|
||||||
|
private Connection $con;
|
||||||
|
|
||||||
|
public function __construct(Connection $con)
|
||||||
|
{
|
||||||
|
$this->con = $con;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addLike($user,$liked):bool
|
||||||
|
{
|
||||||
|
$query = 'INSERT INTO likes VALUES (:user,:liked)';
|
||||||
|
$this->con->executeQuery($query,array(':user'=>array($user,PDO::PARAM_STR),':liked'=>array($liked,PDO::PARAM_STR)));
|
||||||
|
$query = 'SELECT * FROM likes WHERE (user=:user AND liked=:liked) OR (liked=:liked AND user=:user )';
|
||||||
|
$this->con->executeQuery($query,array(':user'=>array($user,PDO::PARAM_STR),':liked'=>array($liked,PDO::PARAM_STR)));
|
||||||
|
$res=$this->con->getResults();
|
||||||
|
if(count($res) == 2) {
|
||||||
|
$query = 'INSERT INTO matches VALUES (:user,:liked)';
|
||||||
|
$this->con->executeQuery($query,array(':user'=>array($user,PDO::PARAM_STR),':liked'=>array($liked,PDO::PARAM_STR)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class UserGateway
|
||||||
|
{
|
||||||
|
private Connection $con;
|
||||||
|
|
||||||
|
public function __construct(Connection $con)
|
||||||
|
{
|
||||||
|
$this->con = $con;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInformations($id): array
|
||||||
|
{
|
||||||
|
$query = 'SELECT idDafl,idSpotify FROM users WHERE idDafl=:id';
|
||||||
|
$this->con->executeQuery($query, array(':id' => array($id, PDO::PARAM_STR)));
|
||||||
|
return $this->con->getResults();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addUser($idDafl, $idSpotify, $passw)
|
||||||
|
{
|
||||||
|
$query = 'INSERT INTO users VALUES (:idDafl,:idSpotify,:passw)';
|
||||||
|
$this->con->executeQuery($query, array(':idDafl' => array($idDafl, PDO::PARAM_STR), ':idSpotify' => array($idSpotify, PDO::PARAM_STR), ':passw' => array($passw, PDO::PARAM_STR)));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use \Psr\Http\Message\ServerRequestInterface as Request;
|
||||||
|
use \Psr\Http\Message\ResponseInterface as Response;
|
||||||
|
|
||||||
|
require "Model.php";
|
||||||
|
require "Connection.php";
|
||||||
|
|
||||||
|
// Get information about a user
|
||||||
|
$app->get('/users/{id}', function (Request $request, Response $response, array $args) {
|
||||||
|
try {
|
||||||
|
$mdl = new Model();
|
||||||
|
$res = $mdl->getInformationsUser($args['id']);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$res = array("Error: " . $e->getMessage());
|
||||||
|
} finally {
|
||||||
|
$response->getBody()->write(json_encode($res));
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add a user
|
||||||
|
$app->post('/users/new', function (Request $request, Response $response, array $args) {
|
||||||
|
try {
|
||||||
|
$mdl = new Model();
|
||||||
|
$data = $request->getParsedBody();
|
||||||
|
if (!isset($data['idDafl']) || !isset($data['idSpotify']) || !isset($data['passw'])) {
|
||||||
|
throw new Exception("missing arguments");
|
||||||
|
}
|
||||||
|
$mdl->addUser($data['idDafl'], $data['idSpotify'], $data['passw']);
|
||||||
|
$res = "Ok";
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$res = array("Error: " . $e->getMessage());
|
||||||
|
} finally {
|
||||||
|
$response->getBody()->write(json_encode($res));
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Update information about a user
|
||||||
|
$app->put('/users/{id}', function (Request $request, Response $response, array $args) {
|
||||||
|
$res = "Update infos of user " . $args['id'];
|
||||||
|
$response->getBody()->write($res);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Delete a user
|
||||||
|
$app->delete('/users/{id}', function (Request $request, Response $response, array $args) {
|
||||||
|
$res = "Delete user " . $args['id'];
|
||||||
|
$response->getBody()->write($res);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
// Like someone
|
||||||
|
$app->post('/user/{id}/like', function (Request $request, Response $response, array $args) {
|
||||||
|
try {
|
||||||
|
$mdl = new Model();
|
||||||
|
$data = $request->getParsedBody();
|
||||||
|
if (!isset($data['liked'])) {
|
||||||
|
throw new Exception("missing arguments");
|
||||||
|
}
|
||||||
|
$res=($mdl->like($args["id"],$data["liked"])) ? "Match" : "Ok";
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$res = array("Error: " . $e->getMessage());
|
||||||
|
} finally {
|
||||||
|
$response->getBody()->write(json_encode($res));
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
/*
|
||||||
|
// Add a new song as a preference for a situation
|
||||||
|
$app->post('/users/{id}/preferences', function (Request $request, Response $response, array $args) {
|
||||||
|
$res = "User " . $args['id'] . " add music " . $args['music'] . " to his preferences for category " . $args['categ'];
|
||||||
|
$response->getBody()->write($res);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
});
|
||||||
|
*/
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"require": {
|
||||||
|
"slim/slim": "3.*",
|
||||||
|
"illuminate/database": "~5.1",
|
||||||
|
"ext-json": "*"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"allow-plugins": {
|
||||||
|
"kylekatarnls/update-helper": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
// Files auto-loading
|
||||||
|
require '../vendor/autoload.php';
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
require '../app/config.php';
|
||||||
|
|
||||||
|
// App instantiation
|
||||||
|
$app = new \Slim\App(['settings' => $config]);
|
||||||
|
|
||||||
|
// Routes
|
||||||
|
require '../app/routes.php';
|
||||||
|
|
||||||
|
// Run
|
||||||
|
$app->run();
|
@ -1,2 +1,2 @@
|
|||||||
FROM httpd:2.4
|
FROM httpd:2.4
|
||||||
COPY ./public-html/ /usr/local/apache2/htdocs/
|
COPY ./sources/ /usr/local/apache2/htdocs/
|
@ -1 +0,0 @@
|
|||||||
Hello world Dafl !
|
|
@ -1,39 +0,0 @@
|
|||||||
{
|
|
||||||
"project_info": {
|
|
||||||
"project_number": "943188299704",
|
|
||||||
"project_id": "daflmusic-b3b74",
|
|
||||||
"storage_bucket": "daflmusic-b3b74.appspot.com"
|
|
||||||
},
|
|
||||||
"client": [
|
|
||||||
{
|
|
||||||
"client_info": {
|
|
||||||
"mobilesdk_app_id": "1:943188299704:android:995199bd5229a330a9c94d",
|
|
||||||
"android_client_info": {
|
|
||||||
"package_name": "com.example.dafl_project_flutter"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"oauth_client": [
|
|
||||||
{
|
|
||||||
"client_id": "943188299704-qp12a784hmdo97v7qq78ekasgrfkmo52.apps.googleusercontent.com",
|
|
||||||
"client_type": 3
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"api_key": [
|
|
||||||
{
|
|
||||||
"current_key": "AIzaSyBehHyqsXbBm1I7fBSG2bPOQvpDX-8Rm7I"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"services": {
|
|
||||||
"appinvite_service": {
|
|
||||||
"other_platform_oauth_client": [
|
|
||||||
{
|
|
||||||
"client_id": "943188299704-qp12a784hmdo97v7qq78ekasgrfkmo52.apps.googleusercontent.com",
|
|
||||||
"client_type": 3
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"configuration_version": "1"
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CLIENT_ID</key>
|
|
||||||
<string>943188299704-h4035qno57lll2km151rdh3bgbb22vk7.apps.googleusercontent.com</string>
|
|
||||||
<key>REVERSED_CLIENT_ID</key>
|
|
||||||
<string>com.googleusercontent.apps.943188299704-h4035qno57lll2km151rdh3bgbb22vk7</string>
|
|
||||||
<key>API_KEY</key>
|
|
||||||
<string>AIzaSyCnQnCeu7gdc1_uIOxXVNQT1pG8xjD_tB8</string>
|
|
||||||
<key>GCM_SENDER_ID</key>
|
|
||||||
<string>943188299704</string>
|
|
||||||
<key>PLIST_VERSION</key>
|
|
||||||
<string>1</string>
|
|
||||||
<key>BUNDLE_ID</key>
|
|
||||||
<string>com.example.daflProjectFlutter</string>
|
|
||||||
<key>PROJECT_ID</key>
|
|
||||||
<string>daflmusic-b3b74</string>
|
|
||||||
<key>STORAGE_BUCKET</key>
|
|
||||||
<string>daflmusic-b3b74.appspot.com</string>
|
|
||||||
<key>IS_ADS_ENABLED</key>
|
|
||||||
<false></false>
|
|
||||||
<key>IS_ANALYTICS_ENABLED</key>
|
|
||||||
<false></false>
|
|
||||||
<key>IS_APPINVITE_ENABLED</key>
|
|
||||||
<true></true>
|
|
||||||
<key>IS_GCM_ENABLED</key>
|
|
||||||
<true></true>
|
|
||||||
<key>IS_SIGNIN_ENABLED</key>
|
|
||||||
<true></true>
|
|
||||||
<key>GOOGLE_APP_ID</key>
|
|
||||||
<string>1:943188299704:ios:bd6866b329aebb64a9c94d</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"file_generated_by": "FlutterFire CLI",
|
|
||||||
"purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory",
|
|
||||||
"GOOGLE_APP_ID": "1:943188299704:ios:bd6866b329aebb64a9c94d",
|
|
||||||
"FIREBASE_PROJECT_ID": "daflmusic-b3b74",
|
|
||||||
"GCM_SENDER_ID": "943188299704"
|
|
||||||
}
|
|
@ -1,300 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
import 'dart:math';
|
|
||||||
import 'package:dafl_project_flutter/main.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
import 'package:crypto/crypto.dart';
|
|
||||||
import 'dart:developer' as dev;
|
|
||||||
import '../exceptions/api_exception.dart';
|
|
||||||
|
|
||||||
class Api {
|
|
||||||
//from dashboard
|
|
||||||
final _clientId = '7ceb49d874b9404492246027e4d68cf8';
|
|
||||||
final _clientSecret = '98f9cb960bf54ebbb9ad306e7ff919cb';
|
|
||||||
|
|
||||||
//for web api
|
|
||||||
get redirectUri => 'https://daflmusic.000webhostapp.com/callback/';
|
|
||||||
final _scopes =
|
|
||||||
'user-read-playback-state user-read-currently-playing user-read-recently-played playlist-modify-public ugc-image-upload user-modify-playback-state';
|
|
||||||
late String _state;
|
|
||||||
dynamic _codeVerifier;
|
|
||||||
dynamic _codeChallenge;
|
|
||||||
late String _encodedLogs;
|
|
||||||
final _tokenType = 'Bearer ';
|
|
||||||
late http.Response _response; //use _setResponse() as kind of a private setter
|
|
||||||
final _playlistName = "Dafl's discovery";
|
|
||||||
|
|
||||||
//from web api
|
|
||||||
String? _code;
|
|
||||||
int? _expiresIn;
|
|
||||||
String? _refreshToken;
|
|
||||||
String? _accessToken; //use _getAccessToken() as kind of a private getter
|
|
||||||
|
|
||||||
//other
|
|
||||||
final _client = http.Client();
|
|
||||||
late Uri _urlAuthorize;
|
|
||||||
|
|
||||||
get urlAuthorize => _urlAuthorize;
|
|
||||||
DateTime? _tokenEnd;
|
|
||||||
|
|
||||||
Api() {
|
|
||||||
_state = _generateRandomString(16);
|
|
||||||
_codeVerifier = _generateRandomString(_generateRandomInt(43, 128));
|
|
||||||
_codeChallenge = _generateCodeChallenge();
|
|
||||||
_encodedLogs = base64.encode(utf8.encode("$_clientId:$_clientSecret"));
|
|
||||||
_urlAuthorize = Uri.https('accounts.spotify.com', 'authorize', {
|
|
||||||
'client_id': _clientId,
|
|
||||||
'response_type': 'code',
|
|
||||||
'redirect_uri': redirectUri,
|
|
||||||
'state': _state,
|
|
||||||
'scope': _scopes,
|
|
||||||
'show_dialog': 'false',
|
|
||||||
'code_challenge_method': 'S256',
|
|
||||||
'code_challenge': _codeChallenge
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//PKCE generations
|
|
||||||
|
|
||||||
_generateRandomInt(int min, int max) {
|
|
||||||
return min + Random().nextInt(max - min);
|
|
||||||
}
|
|
||||||
|
|
||||||
_generateRandomString(int length) {
|
|
||||||
const chars =
|
|
||||||
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';
|
|
||||||
return String.fromCharCodes(Iterable.generate(
|
|
||||||
length, (_) => chars.codeUnitAt(Random().nextInt(chars.length))));
|
|
||||||
}
|
|
||||||
|
|
||||||
_generateCodeChallenge() {
|
|
||||||
return base64Encode(sha256.convert(utf8.encode(_codeVerifier)).bytes)
|
|
||||||
.replaceAll('+', '-')
|
|
||||||
.replaceAll('/', '_')
|
|
||||||
.replaceAll('=', '');
|
|
||||||
}
|
|
||||||
|
|
||||||
//session management
|
|
||||||
|
|
||||||
requestUserAuthorization(Uri url) async {
|
|
||||||
if (url.queryParameters['state'] != _state.toString()) {
|
|
||||||
throw ApiException('state');
|
|
||||||
}
|
|
||||||
_code = url.queryParameters['code'];
|
|
||||||
await _requestAccessToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
_requestAccessToken() async {
|
|
||||||
var urlToken = Uri.https('accounts.spotify.com', 'api/token', {
|
|
||||||
'code': _code,
|
|
||||||
'redirect_uri': redirectUri,
|
|
||||||
'grant_type': 'authorization_code',
|
|
||||||
'client_id': _clientId,
|
|
||||||
'code_verifier': _codeVerifier
|
|
||||||
});
|
|
||||||
_setResponse(await _client.post(urlToken, headers: <String, String>{
|
|
||||||
'Authorization': 'Basic $_encodedLogs',
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded'
|
|
||||||
}));
|
|
||||||
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
|
|
||||||
_accessToken = decodedResponse['access_token'];
|
|
||||||
_expiresIn = decodedResponse['expires_in'];
|
|
||||||
_tokenEnd = DateTime.now().add(Duration(seconds: _expiresIn!));
|
|
||||||
_refreshToken = decodedResponse['refresh_token'];
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String?> _getAccessToken() async {
|
|
||||||
if (DateTime.now().isAfter(_tokenEnd!)) {
|
|
||||||
await _getRefreshedAccessToken();
|
|
||||||
}
|
|
||||||
return _accessToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
_setResponse(value) {
|
|
||||||
int sc = value.statusCode;
|
|
||||||
if (sc >= 300) {
|
|
||||||
dev.log(value.body.toString());
|
|
||||||
throw ApiException(sc);
|
|
||||||
}
|
|
||||||
_response = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
_getRefreshedAccessToken() async {
|
|
||||||
var urlToken = Uri.https('accounts.spotify.com', 'api/token', {
|
|
||||||
'grant_type': 'refresh_token',
|
|
||||||
'refresh_token': _refreshToken,
|
|
||||||
'client_id': _clientId
|
|
||||||
});
|
|
||||||
_setResponse(await _client.post(urlToken, headers: <String, String>{
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded'
|
|
||||||
}));
|
|
||||||
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
|
|
||||||
_accessToken = decodedResponse['access_token'];
|
|
||||||
_expiresIn = decodedResponse['expires_in'];
|
|
||||||
_tokenEnd = DateTime.now().add(Duration(seconds: _expiresIn!));
|
|
||||||
}
|
|
||||||
|
|
||||||
//functional methods
|
|
||||||
|
|
||||||
Future<String> getCurrentlyPlayingTrack() async {
|
|
||||||
var url = Uri.https('api.spotify.com', 'v1/me/player/currently-playing');
|
|
||||||
var token = await _getAccessToken();
|
|
||||||
var response = await _client.get(url, headers: <String, String>{
|
|
||||||
'Authorization': '$_tokenType $token',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
});
|
|
||||||
if (response.statusCode == 204) {
|
|
||||||
return _getRecentlyPlayedTrack();
|
|
||||||
}
|
|
||||||
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
|
||||||
return decodedResponse['item']['id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String> _getRecentlyPlayedTrack() async {
|
|
||||||
var url = Uri.https(
|
|
||||||
'api.spotify.com', 'v1/me/player/recently-played', {'limit': '1'});
|
|
||||||
var token = await _getAccessToken();
|
|
||||||
_setResponse(await _client.get(url, headers: <String, String>{
|
|
||||||
'Authorization': '$_tokenType $token',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}));
|
|
||||||
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
|
|
||||||
return decodedResponse['items'][0]['track']['id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Map> getTrackInfo(String id) async {
|
|
||||||
var url = Uri.https('api.spotify.com', 'v1/tracks/$id');
|
|
||||||
var token = await _getAccessToken();
|
|
||||||
_setResponse(await _client.get(url, headers: <String, String>{
|
|
||||||
'Authorization': '$_tokenType $token',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}));
|
|
||||||
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
|
|
||||||
Map<String, String> info = {
|
|
||||||
'artist': decodedResponse['artists'][0]['name'],
|
|
||||||
'name': decodedResponse['name'],
|
|
||||||
'cover': decodedResponse['album']['images'][0]['url']
|
|
||||||
};
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> _isInPlaylist(String idTrack, String idPlaylist) async {
|
|
||||||
var url = Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks',
|
|
||||||
{'limit': '50', 'fields': 'items(track(id))'});
|
|
||||||
var token = await _getAccessToken();
|
|
||||||
_setResponse(await _client.get(url, headers: <String, String>{
|
|
||||||
'Authorization': '$_tokenType $token',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}));
|
|
||||||
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
|
|
||||||
var res = decodedResponse['items']
|
|
||||||
.where((element) => element['track']['id'] == idTrack)
|
|
||||||
.toList();
|
|
||||||
if (res.length >= 1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
addToPLaylist(String idTrack) async {
|
|
||||||
var idPlaylist = await _getPlaylist();
|
|
||||||
if (idPlaylist == null) {
|
|
||||||
idPlaylist = await _createPlaylist();
|
|
||||||
} else {
|
|
||||||
if (await _isInPlaylist(idTrack, idPlaylist)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var token = await _getAccessToken();
|
|
||||||
var url = Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks',
|
|
||||||
{'uris': 'spotify:track:$idTrack'});
|
|
||||||
_setResponse(await _client.post(url, headers: <String, String>{
|
|
||||||
'Authorization': '$_tokenType $token',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String?> _getPlaylist() async {
|
|
||||||
var url = Uri.https('api.spotify.com', 'v1/me/playlists', {'limit': '50'});
|
|
||||||
var token = await _getAccessToken();
|
|
||||||
_setResponse(await _client.get(url, headers: <String, String>{
|
|
||||||
'Authorization': '$_tokenType $token',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}));
|
|
||||||
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
|
|
||||||
var daflplaylist = decodedResponse['items']
|
|
||||||
.where((element) => element['name'] == _playlistName)
|
|
||||||
.toList();
|
|
||||||
if (daflplaylist.length == 1) {
|
|
||||||
return daflplaylist[0]['uri'].substring(
|
|
||||||
17); //17 char because format is 'spotify:playlist:MYPLAYLISTID'
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String> _createPlaylist() async {
|
|
||||||
var idUser = await MyApp.controller.currentUser.getIdSpotify();
|
|
||||||
var token = await _getAccessToken();
|
|
||||||
var url = Uri.https('api.spotify.com', 'v1/users/$idUser/playlists');
|
|
||||||
_setResponse(await _client.post(url,
|
|
||||||
headers: <String, String>{
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Authorization': '$_tokenType $token',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: jsonEncode(<String, String>{
|
|
||||||
'name': _playlistName,
|
|
||||||
'description':
|
|
||||||
'Retrouvez toutes vos découvertes faites sur DaflMusic 🎵',
|
|
||||||
'public': 'true'
|
|
||||||
})));
|
|
||||||
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
|
|
||||||
var idPlaylist = decodedResponse['id'];
|
|
||||||
return idPlaylist;
|
|
||||||
}
|
|
||||||
|
|
||||||
playTrack(String idTrack) async {
|
|
||||||
var token = await _getAccessToken();
|
|
||||||
var url = Uri.https('api.spotify.com', 'v1/me/player/play');
|
|
||||||
_setResponse(await _client.put(url,
|
|
||||||
headers: <String, String>{
|
|
||||||
'Authorization': '$_tokenType $token',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: jsonEncode(<String, List>{
|
|
||||||
'uris': ['spotify:track:$idTrack']
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
|
|
||||||
removeFromPlaylist(String idTrack) async {
|
|
||||||
var idPlaylist = await _getPlaylist();
|
|
||||||
if (idPlaylist != null) {
|
|
||||||
if (await _isInPlaylist(idTrack, idPlaylist)) {
|
|
||||||
var token = await _getAccessToken();
|
|
||||||
var url =
|
|
||||||
Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks');
|
|
||||||
var jsonVar = jsonEncode(<String, List>{
|
|
||||||
'tracks': [
|
|
||||||
{'uri': 'spotify:track:$idTrack'}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
_setResponse(await _client.delete(url,
|
|
||||||
headers: <String, String>{
|
|
||||||
'Authorization': '$_tokenType $token',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: jsonVar));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String> getIdUser() async {
|
|
||||||
var url = Uri.https('api.spotify.com', 'v1/me');
|
|
||||||
var token = await _getAccessToken();
|
|
||||||
_setResponse(await _client.get(url, headers: <String, String>{
|
|
||||||
'Authorization': '$_tokenType $token',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}));
|
|
||||||
var decodedResponse = jsonDecode(utf8.decode(_response.bodyBytes)) as Map;
|
|
||||||
return decodedResponse['id'];
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,11 @@
|
|||||||
|
import 'dart:collection';
|
||||||
|
|
||||||
|
import '../model/music.dart';
|
||||||
|
import '../model/spot.dart';
|
||||||
|
|
||||||
|
class LiveData {
|
||||||
|
bool discoveriesSortChoice = true;
|
||||||
|
late LinkedHashMap<Music, DateTime> discoveries;
|
||||||
|
late List<Spot> spots;
|
||||||
|
late Music userCurrentMusic;
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
import 'dart:developer' as dev;
|
|
||||||
|
|
||||||
class ApiException implements Exception {
|
|
||||||
final String mess = 'Api exception raised,';
|
|
||||||
|
|
||||||
ApiException(dynamic code) {
|
|
||||||
if (code.runtimeType == String) {
|
|
||||||
dev.log('$mess state verification failed.');
|
|
||||||
} else {
|
|
||||||
dev.log('$mess status code : $code.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,7 @@
|
|||||||
|
import 'dart:developer' as dev;
|
||||||
|
|
||||||
|
class ApiStateException implements Exception {
|
||||||
|
ApiStateException() {
|
||||||
|
dev.log('State verification failed.');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
import 'dart:developer' as dev;
|
||||||
|
import 'package:http/http.dart';
|
||||||
|
|
||||||
|
class HttpException implements Exception {
|
||||||
|
HttpException(var value) {
|
||||||
|
dev.log('Http request failed');
|
||||||
|
if (value.runtimeType == Response) {
|
||||||
|
dev.log('Status code : ${value.statusCode.toString()}');
|
||||||
|
dev.log('Body : ${value.body.toString()}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,69 +0,0 @@
|
|||||||
// File generated by FlutterFire CLI.
|
|
||||||
// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members
|
|
||||||
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
|
|
||||||
import 'package:flutter/foundation.dart'
|
|
||||||
show defaultTargetPlatform, kIsWeb, TargetPlatform;
|
|
||||||
|
|
||||||
/// Default [FirebaseOptions] for use with your Firebase apps.
|
|
||||||
///
|
|
||||||
/// Example:
|
|
||||||
/// ```dart
|
|
||||||
/// import 'firebase_options.dart';
|
|
||||||
/// // ...
|
|
||||||
/// await Firebase.initializeApp(
|
|
||||||
/// options: DefaultFirebaseOptions.currentPlatform,
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
class DefaultFirebaseOptions {
|
|
||||||
static FirebaseOptions get currentPlatform {
|
|
||||||
if (kIsWeb) {
|
|
||||||
throw UnsupportedError(
|
|
||||||
'DefaultFirebaseOptions have not been configured for web - '
|
|
||||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
switch (defaultTargetPlatform) {
|
|
||||||
case TargetPlatform.android:
|
|
||||||
return android;
|
|
||||||
case TargetPlatform.iOS:
|
|
||||||
return ios;
|
|
||||||
case TargetPlatform.macOS:
|
|
||||||
throw UnsupportedError(
|
|
||||||
'DefaultFirebaseOptions have not been configured for macos - '
|
|
||||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
|
||||||
);
|
|
||||||
case TargetPlatform.windows:
|
|
||||||
throw UnsupportedError(
|
|
||||||
'DefaultFirebaseOptions have not been configured for windows - '
|
|
||||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
|
||||||
);
|
|
||||||
case TargetPlatform.linux:
|
|
||||||
throw UnsupportedError(
|
|
||||||
'DefaultFirebaseOptions have not been configured for linux - '
|
|
||||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
throw UnsupportedError(
|
|
||||||
'DefaultFirebaseOptions are not supported for this platform.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const FirebaseOptions android = FirebaseOptions(
|
|
||||||
apiKey: 'AIzaSyBehHyqsXbBm1I7fBSG2bPOQvpDX-8Rm7I',
|
|
||||||
appId: '1:943188299704:android:995199bd5229a330a9c94d',
|
|
||||||
messagingSenderId: '943188299704',
|
|
||||||
projectId: 'daflmusic-b3b74',
|
|
||||||
storageBucket: 'daflmusic-b3b74.appspot.com',
|
|
||||||
);
|
|
||||||
|
|
||||||
static const FirebaseOptions ios = FirebaseOptions(
|
|
||||||
apiKey: 'AIzaSyCnQnCeu7gdc1_uIOxXVNQT1pG8xjD_tB8',
|
|
||||||
appId: '1:943188299704:ios:bd6866b329aebb64a9c94d',
|
|
||||||
messagingSenderId: '943188299704',
|
|
||||||
projectId: 'daflmusic-b3b74',
|
|
||||||
storageBucket: 'daflmusic-b3b74.appspot.com',
|
|
||||||
iosClientId: '943188299704-h4035qno57lll2km151rdh3bgbb22vk7.apps.googleusercontent.com',
|
|
||||||
iosBundleId: 'com.example.daflProjectFlutter',
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
import 'package:dafl_project_flutter/model/message.dart';
|
|
||||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
||||||
|
|
||||||
class MessageDatabaseServices {
|
|
||||||
// Make an unique chat ID between 2 client. Look like 'User1-User2'
|
|
||||||
String _getChatId(String idSender, String idReceiver) {
|
|
||||||
// Test to always have the same id
|
|
||||||
if (idSender.hashCode <= idReceiver.hashCode)
|
|
||||||
return '$idSender-${idReceiver}';
|
|
||||||
else
|
|
||||||
return '${idReceiver}-$idSender';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send a message from an user to an other
|
|
||||||
void sendMessage(Message message, String idSender, String idReceiver) {
|
|
||||||
String chatId = _getChatId(idSender, idReceiver);
|
|
||||||
|
|
||||||
var documentReference = FirebaseFirestore.instance
|
|
||||||
.collection('messages')
|
|
||||||
.doc(chatId)
|
|
||||||
.collection(chatId)
|
|
||||||
.doc(DateTime
|
|
||||||
.now()
|
|
||||||
.millisecondsSinceEpoch
|
|
||||||
.toString());
|
|
||||||
|
|
||||||
FirebaseFirestore.instance.runTransaction((transaction) async {
|
|
||||||
transaction.set(documentReference, message.toHashMap());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a message from a snapshot Firestore
|
|
||||||
Message _getMessage(DocumentSnapshot<Map<String, dynamic>> snapshot) {
|
|
||||||
var data = snapshot.data();
|
|
||||||
if (data == null) throw Exception("no data in database");
|
|
||||||
|
|
||||||
return Message.fromMap(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a list of messages from Firestore
|
|
||||||
List<Message> _getAllMessages(QuerySnapshot<Map<String, dynamic>> snapshot) {
|
|
||||||
return snapshot.docs.map((doc) {
|
|
||||||
return _getMessage(doc);
|
|
||||||
}).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the massages from Firestore
|
|
||||||
Stream<List<Message>> getMessage(String idSender, String idReceiver) {
|
|
||||||
String chatId = _getChatId(idSender, idReceiver);
|
|
||||||
|
|
||||||
return FirebaseFirestore.instance
|
|
||||||
.collection('messages')
|
|
||||||
.doc(chatId)
|
|
||||||
.collection(chatId)
|
|
||||||
.snapshots()
|
|
||||||
.map(_getAllMessages);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
|
||||||
|
|
||||||
class NotificationService {
|
|
||||||
static void initialize() {
|
|
||||||
FirebaseMessaging.instance.requestPermission();
|
|
||||||
|
|
||||||
FirebaseMessaging.onMessage.listen((event) {
|
|
||||||
print('A new onMessage event was published!');
|
|
||||||
});
|
|
||||||
|
|
||||||
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
|
|
||||||
print('A new onMessageOpenedApp event was published!');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<String?> getToken() async {
|
|
||||||
return FirebaseMessaging.instance.getToken(
|
|
||||||
vapidKey:
|
|
||||||
"BOxfduRivQnT8TS1h9WRGEk4gV2IOzJpTCcoKxVTMgVWjxi6TUcQBng2mqM7fUfNy51esFrRGE68coa0XZaKdHc");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +1,8 @@
|
|||||||
import 'user.dart';
|
import 'user.dart';
|
||||||
|
|
||||||
class Message {
|
class Message {
|
||||||
String idSender;
|
String senderId;
|
||||||
String idReceiver;
|
|
||||||
String content;
|
String content;
|
||||||
|
|
||||||
Message({
|
Message(this.senderId, this.content);
|
||||||
required this.idSender,
|
|
||||||
required this.idReceiver,
|
|
||||||
required this.content,
|
|
||||||
});
|
|
||||||
|
|
||||||
Map<String, dynamic> toHashMap() {
|
|
||||||
return {
|
|
||||||
'idSender': idSender,
|
|
||||||
'idReceiver': idReceiver,
|
|
||||||
'content': content,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
factory Message.fromMap(Map<String, dynamic> data) {
|
|
||||||
return Message(
|
|
||||||
idSender: data['idSender'],
|
|
||||||
idReceiver: data['idReceiver'],
|
|
||||||
content: data['content'],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return "idSender : $idSender " + "Content : $content \n";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,74 +1,8 @@
|
|||||||
import 'dart:async';
|
|
||||||
import '../position/location.dart';
|
|
||||||
import '../exceptions/api_exception.dart';
|
|
||||||
import '../main.dart';
|
|
||||||
import 'music.dart';
|
|
||||||
import 'spot.dart';
|
|
||||||
import 'package:collection/collection.dart';
|
|
||||||
|
|
||||||
class User {
|
class User {
|
||||||
Timer? timer;
|
|
||||||
int test = 0;
|
|
||||||
|
|
||||||
//attributes from DAFL
|
//attributes from DAFL
|
||||||
late String usernameDafl;
|
String idDafl;
|
||||||
late String passwDafl;
|
late String idSpotify;
|
||||||
List<Music> discovery = [];
|
|
||||||
List<Spot> spots = [];
|
|
||||||
|
|
||||||
//attributes with Spotify API
|
|
||||||
String? _idSpotify; //use _getIdUser() as kind of a private getter
|
|
||||||
late Music _currentMusic;
|
|
||||||
bool sortChoise = true;
|
|
||||||
|
|
||||||
|
|
||||||
//constructors
|
//constructors
|
||||||
User(this.usernameDafl, this.passwDafl) {
|
User(this.idDafl);
|
||||||
actualiseCurrentMusic();
|
|
||||||
}
|
|
||||||
|
|
||||||
Music get currentMusic => _currentMusic; //lists
|
|
||||||
|
|
||||||
Future<String> getIdSpotify() async {
|
|
||||||
_idSpotify ??= await MyApp.api.getIdUser();
|
|
||||||
return _idSpotify!;
|
|
||||||
}
|
|
||||||
|
|
||||||
addDiscovery(Music music) {
|
|
||||||
discovery.add(music);
|
|
||||||
}
|
|
||||||
|
|
||||||
actualiseCurrentMusic() async {
|
|
||||||
try {
|
|
||||||
_currentMusic = Music(await MyApp.api.getCurrentlyPlayingTrack());
|
|
||||||
} on ApiException {
|
|
||||||
// TODO : add notification to show that an error occurred
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
listSpots() {
|
|
||||||
print('ajout test');
|
|
||||||
Future<String> rep = Location.sendCurrentLocation();
|
|
||||||
//ex : dorian-2d2s52a15d2a5,audric-2x5s2az3d1s5wx5s1,lucas-s2a5d25a2a25d
|
|
||||||
|
|
||||||
rep.then((String result) {
|
|
||||||
List<String> tab = result.split(",");
|
|
||||||
//ex : [dorian-2d2s52a15d2a5 , audric-2x5s2az3d1s5wx5s1 , lucas-s2a5d25a2a25d]
|
|
||||||
|
|
||||||
for (var element in tab) {
|
|
||||||
List<String> tab2 = element.split("-");
|
|
||||||
spots.add(Spot(tab2[0], Music(tab2[1])));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getListSpots() {
|
|
||||||
if (test == 0) {
|
|
||||||
test = 1;
|
|
||||||
listSpots();
|
|
||||||
} else {
|
|
||||||
timer =
|
|
||||||
Timer.periodic(const Duration(seconds: 72), (Timer t) => listSpots());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
import '../model/user.dart';
|
|
||||||
|
|
||||||
abstract class Loader {
|
|
||||||
Future<User> load(String username, String password);
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
import '../model/user.dart';
|
|
||||||
|
|
||||||
abstract class Saver{
|
|
||||||
void save(User userToSave);
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
abstract class Searcher {
|
|
||||||
Future<bool> searchUser(String? username, String? password);
|
|
||||||
|
|
||||||
Future<bool> searchByUsername(String? username);
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
import 'package:geolocator/geolocator.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:async';
|
|
||||||
import '../main.dart';
|
|
||||||
|
|
||||||
class Location {
|
|
||||||
static Future<String> sendCurrentLocation() async {
|
|
||||||
Uri uri = Uri.parse("http://89.83.53.34/phpmyadmin/dafldev/insert.php");
|
|
||||||
LocationPermission permission;
|
|
||||||
permission = await Geolocator.checkPermission();
|
|
||||||
if (permission == LocationPermission.denied) {
|
|
||||||
permission = await Geolocator.requestPermission();
|
|
||||||
if (permission == LocationPermission.deniedForever) {
|
|
||||||
//faire l'interface gra pour gérer ça
|
|
||||||
return Future.error('Location Not Available');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String actualUser = MyApp.controller.currentUser.usernameDafl;
|
|
||||||
String actualSong = await MyApp.api.getCurrentlyPlayingTrack();
|
|
||||||
Position current = await Geolocator.getCurrentPosition();
|
|
||||||
await http.post(uri, body: {
|
|
||||||
"id": actualUser.toString(),
|
|
||||||
"latitude": current.latitude.toString(),
|
|
||||||
"longitude": current.longitude.toString(),
|
|
||||||
"idMusic": actualSong.toString(),
|
|
||||||
});
|
|
||||||
return getData();
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future<String> getData() async {
|
|
||||||
String actualUser = MyApp.controller.currentUser.usernameDafl;
|
|
||||||
Uri uri = Uri.parse("http://89.83.53.34/phpmyadmin/dafldev/distance.php");
|
|
||||||
http.Response response = await http.post(uri, body: {
|
|
||||||
"id": actualUser,
|
|
||||||
});
|
|
||||||
var data = jsonDecode(response.body);
|
|
||||||
return data.toString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,20 @@
|
|||||||
|
import 'package:dafl_project_flutter/services/api/api_spotify_identification.dart';
|
||||||
|
import 'package:dafl_project_flutter/services/api/api_spotify_requests.dart';
|
||||||
|
|
||||||
|
class ApiSpotify {
|
||||||
|
late ApiSpotifyIdentification _identification;
|
||||||
|
late ApiSpotifyRequests _requests;
|
||||||
|
|
||||||
|
ApiSpotify() {
|
||||||
|
_identification = ApiSpotifyIdentification();
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiSpotifyIdentification get identification => _identification;
|
||||||
|
|
||||||
|
ApiSpotifyRequests get requests => _requests;
|
||||||
|
|
||||||
|
apiAuthorization(url) async {
|
||||||
|
await _identification.setCode(url);
|
||||||
|
_requests = ApiSpotifyRequests(await _identification.createToken());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:math';
|
||||||
|
import '../../exceptions/api_state_exception.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:crypto/crypto.dart';
|
||||||
|
import '../http_response_verification.dart';
|
||||||
|
import 'token_spotify.dart';
|
||||||
|
|
||||||
|
class ApiSpotifyIdentification extends HttpResponseVerification {
|
||||||
|
static const String clientId = '7ceb49d874b9404492246027e4d68cf8';
|
||||||
|
final String _clientSecret = '98f9cb960bf54ebbb9ad306e7ff919cb';
|
||||||
|
final String _scopes =
|
||||||
|
'user-read-playback-state user-read-currently-playing user-read-recently-played playlist-modify-public ugc-image-upload user-modify-playback-state';
|
||||||
|
|
||||||
|
late String _state;
|
||||||
|
late String _codeVerifier;
|
||||||
|
late String _codeChallenge;
|
||||||
|
late String _encodedLogs;
|
||||||
|
|
||||||
|
String? _code;
|
||||||
|
|
||||||
|
String get redirectUri => 'https://codefirst.iut.uca.fr/containers/apiredirect-felixmielcarek/';
|
||||||
|
|
||||||
|
Uri get urlAuthorize => Uri.https('accounts.spotify.com', 'authorize', {
|
||||||
|
'client_id': clientId,
|
||||||
|
'response_type': 'code',
|
||||||
|
'redirect_uri': redirectUri,
|
||||||
|
'state': _state,
|
||||||
|
'scope': _scopes,
|
||||||
|
'show_dialog': 'false',
|
||||||
|
'code_challenge_method': 'S256',
|
||||||
|
'code_challenge': _codeChallenge
|
||||||
|
});
|
||||||
|
|
||||||
|
ApiSpotifyIdentification() {
|
||||||
|
_state = _generateRandomString(16);
|
||||||
|
_codeVerifier = _generateRandomString(_generateRandomInt(43, 128));
|
||||||
|
_codeChallenge = _generateCodeChallenge();
|
||||||
|
_encodedLogs = base64.encode(utf8.encode("$clientId:$_clientSecret"));
|
||||||
|
}
|
||||||
|
|
||||||
|
_generateRandomInt(int min, int max) {
|
||||||
|
return min + Random().nextInt(max - min);
|
||||||
|
}
|
||||||
|
|
||||||
|
_generateRandomString(int length) {
|
||||||
|
const chars =
|
||||||
|
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';
|
||||||
|
return String.fromCharCodes(Iterable.generate(
|
||||||
|
length, (_) => chars.codeUnitAt(Random().nextInt(chars.length))));
|
||||||
|
}
|
||||||
|
|
||||||
|
_generateCodeChallenge() {
|
||||||
|
return base64Encode(sha256.convert(utf8.encode(_codeVerifier)).bytes)
|
||||||
|
.replaceAll('+', '-')
|
||||||
|
.replaceAll('/', '_')
|
||||||
|
.replaceAll('=', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
setCode(Uri url) async {
|
||||||
|
if (url.queryParameters['state'] != _state.toString()) {
|
||||||
|
throw ApiStateException();
|
||||||
|
}
|
||||||
|
_code = url.queryParameters['code'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<TokenSpotify> createToken() async {
|
||||||
|
var urlToken = Uri.https('accounts.spotify.com', 'api/token', {
|
||||||
|
'code': _code,
|
||||||
|
'redirect_uri': redirectUri,
|
||||||
|
'grant_type': 'authorization_code',
|
||||||
|
'client_id': clientId,
|
||||||
|
'code_verifier': _codeVerifier
|
||||||
|
});
|
||||||
|
setResponse(await http.post(urlToken, headers: <String, String>{
|
||||||
|
'Authorization': 'Basic $_encodedLogs',
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
}));
|
||||||
|
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||||
|
return TokenSpotify(decodedResponse['access_token'],
|
||||||
|
decodedResponse['refresh_token'], decodedResponse['expires_in']);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,184 @@
|
|||||||
|
import 'dart:collection';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:dafl_project_flutter/services/api/token_spotify.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
import '../../main.dart';
|
||||||
|
import '../http_response_verification.dart';
|
||||||
|
|
||||||
|
class ApiSpotifyRequests extends HttpResponseVerification {
|
||||||
|
final String _tokenType = 'Bearer ';
|
||||||
|
final String _playlistName = "Dafl's discovery";
|
||||||
|
final TokenSpotify _token;
|
||||||
|
|
||||||
|
ApiSpotifyRequests(this._token);
|
||||||
|
|
||||||
|
Future<String> getCurrentlyPlayingTrack() async {
|
||||||
|
var url = Uri.https('api.spotify.com', 'v1/me/player/currently-playing');
|
||||||
|
var token = await _token.getAccessToken();
|
||||||
|
var response = await http.get(url, headers: <String, String>{
|
||||||
|
'Authorization': '$_tokenType $token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
});
|
||||||
|
if (response.statusCode == 204) {
|
||||||
|
return _getRecentlyPlayedTrack();
|
||||||
|
}
|
||||||
|
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||||
|
return decodedResponse['item']['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> _getRecentlyPlayedTrack() async {
|
||||||
|
var url = Uri.https(
|
||||||
|
'api.spotify.com', 'v1/me/player/recently-played', {'limit': '1'});
|
||||||
|
var token = await _token.getAccessToken();
|
||||||
|
setResponse(await http.get(url, headers: <String, String>{
|
||||||
|
'Authorization': '$_tokenType $token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}));
|
||||||
|
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||||
|
return decodedResponse['items'][0]['track']['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Map> getTrackInfo(String id) async {
|
||||||
|
var url = Uri.https('api.spotify.com', 'v1/tracks/$id');
|
||||||
|
var token = await _token.getAccessToken();
|
||||||
|
setResponse(await http.get(url, headers: <String, String>{
|
||||||
|
'Authorization': '$_tokenType $token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}));
|
||||||
|
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||||
|
Map<String, String> infos = {
|
||||||
|
'artist': decodedResponse['artists'][0]['name'],
|
||||||
|
'name': decodedResponse['name'],
|
||||||
|
'cover': decodedResponse['album']['images'][0]['url']
|
||||||
|
};
|
||||||
|
return infos;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> getIdUser() async {
|
||||||
|
var url = Uri.https('api.spotify.com', 'v1/me');
|
||||||
|
var token = await _token.getAccessToken();
|
||||||
|
setResponse(await http.get(url, headers: <String, String>{
|
||||||
|
'Authorization': '$_tokenType $token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}));
|
||||||
|
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||||
|
return decodedResponse['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
playTrack(String idTrack) async {
|
||||||
|
var token = await _token.getAccessToken();
|
||||||
|
var url = Uri.https('api.spotify.com', 'v1/me/player/play');
|
||||||
|
setResponse(await http.put(url,
|
||||||
|
headers: <String, String>{
|
||||||
|
'Authorization': '$_tokenType $token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: jsonEncode(<String, List>{
|
||||||
|
'uris': ['spotify:track:$idTrack']
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> _getPlaylistId() async {
|
||||||
|
var url = Uri.https('api.spotify.com', 'v1/me/playlists', {'limit': '50'});
|
||||||
|
var token = await _token.getAccessToken();
|
||||||
|
setResponse(await http.get(url, headers: <String, String>{
|
||||||
|
'Authorization': '$_tokenType $token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}));
|
||||||
|
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||||
|
var daflPlaylist = decodedResponse['items']
|
||||||
|
.where((element) => element['name'] == _playlistName)
|
||||||
|
.toList();
|
||||||
|
if (daflPlaylist.length == 1) {
|
||||||
|
return daflPlaylist[0]['uri'].substring(
|
||||||
|
17); //17 char because format is 'spotify:playlist:MYPLAYLISTID'
|
||||||
|
}
|
||||||
|
return await _createPlaylist();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> _createPlaylist() async {
|
||||||
|
var idUser = MyApp.controller.getIdSpotify();
|
||||||
|
var token = await _token.getAccessToken();
|
||||||
|
var url = Uri.https('api.spotify.com', 'v1/users/$idUser/playlists');
|
||||||
|
setResponse(await http.post(url,
|
||||||
|
headers: <String, String>{
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Authorization': '$_tokenType $token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: jsonEncode(<String, String>{
|
||||||
|
'name': _playlistName,
|
||||||
|
'description':
|
||||||
|
'Retrouvez toutes vos découvertes faites sur DaflMusic 🎵',
|
||||||
|
'public': 'true'
|
||||||
|
})));
|
||||||
|
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||||
|
var idPlaylist = decodedResponse['id'];
|
||||||
|
return idPlaylist;
|
||||||
|
}
|
||||||
|
|
||||||
|
addToPlaylist(String idTrack) async {
|
||||||
|
var idPlaylist = await _getPlaylistId();
|
||||||
|
if (await _isInPlaylist(idTrack, idPlaylist)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var token = await _token.getAccessToken();
|
||||||
|
var url = Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks',
|
||||||
|
{'uris': 'spotify:track:$idTrack'});
|
||||||
|
setResponse(await http.post(url, headers: <String, String>{
|
||||||
|
'Authorization': '$_tokenType $token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _isInPlaylist(String idTrack, String idPlaylist) async {
|
||||||
|
var url = Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks',
|
||||||
|
{'limit': '50', 'fields': 'items(track(id))'});
|
||||||
|
var token = await _token.getAccessToken();
|
||||||
|
setResponse(await http.get(url, headers: <String, String>{
|
||||||
|
'Authorization': '$_tokenType $token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}));
|
||||||
|
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||||
|
var res = decodedResponse['items']
|
||||||
|
.where((element) => element['track']['id'] == idTrack)
|
||||||
|
.toList();
|
||||||
|
return (res.length >= 1) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeFromPlaylist(String idTrack) async {
|
||||||
|
var idPlaylist = await _getPlaylistId();
|
||||||
|
if (await _isInPlaylist(idTrack, idPlaylist)) {
|
||||||
|
var token = await _token.getAccessToken();
|
||||||
|
var url = Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks');
|
||||||
|
var jsonVar = jsonEncode(<String, List>{
|
||||||
|
'tracks': [
|
||||||
|
{'uri': 'spotify:track:$idTrack'}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
setResponse(await http.delete(url,
|
||||||
|
headers: <String, String>{
|
||||||
|
'Authorization': '$_tokenType $token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: jsonVar));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<LinkedHashMap<String, DateTime>> getPlaylistTracks() async {
|
||||||
|
var idPlaylist = await _getPlaylistId();
|
||||||
|
var url = Uri.https('api.spotify.com', 'v1/playlists/$idPlaylist/tracks',
|
||||||
|
{'fields': 'items(track(id),added_at)'});
|
||||||
|
var token = await _token.getAccessToken();
|
||||||
|
setResponse(await http.get(url, headers: <String, String>{
|
||||||
|
'Authorization': '$_tokenType $token',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}));
|
||||||
|
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||||
|
LinkedHashMap<String, DateTime> mapRes = LinkedHashMap();
|
||||||
|
decodedResponse['items'].toList().forEach((elem) =>
|
||||||
|
{mapRes[elem['track']['id']] = DateTime.parse(elem['added_at'])});
|
||||||
|
return mapRes;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:dafl_project_flutter/services/api/api_spotify_identification.dart';
|
||||||
|
|
||||||
|
import '../http_response_verification.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
class TokenSpotify extends HttpResponseVerification {
|
||||||
|
String _accessToken;
|
||||||
|
final String _refreshToken;
|
||||||
|
late DateTime _tokenEnd;
|
||||||
|
|
||||||
|
TokenSpotify(this._accessToken, this._refreshToken, int expiresIn) {
|
||||||
|
_setTokenEnd(expiresIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
_setTokenEnd(int expiresIn) {
|
||||||
|
_tokenEnd = DateTime.now().add(Duration(seconds: expiresIn));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> getAccessToken() async {
|
||||||
|
if (DateTime.now().isAfter(_tokenEnd)) {
|
||||||
|
await _actualiseToken();
|
||||||
|
}
|
||||||
|
return _accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
_actualiseToken() async {
|
||||||
|
var urlToken = Uri.https('accounts.spotify.com', 'api/token', {
|
||||||
|
'grant_type': 'refresh_token',
|
||||||
|
'refresh_token': _refreshToken,
|
||||||
|
'client_id': ApiSpotifyIdentification.clientId
|
||||||
|
});
|
||||||
|
setResponse(await http.post(urlToken, headers: <String, String>{
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
}));
|
||||||
|
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
|
||||||
|
_accessToken = decodedResponse['access_token'];
|
||||||
|
_setTokenEnd(decodedResponse['expires_in']);
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +1,25 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'loader.dart';
|
import 'loader.dart';
|
||||||
import '../model/user.dart';
|
import '../../model/user.dart';
|
||||||
import 'database_connexion.dart';
|
import 'database_connexion.dart';
|
||||||
import 'dart:developer' as dev;
|
import 'dart:developer' as dev;
|
||||||
|
|
||||||
class DatabaseLoader extends Loader {
|
class DatabaseLoader implements Loader {
|
||||||
// Load an user from database
|
// Load an user from database
|
||||||
@override
|
@override
|
||||||
Future<User> load(String username, String password) async {
|
Future<User?> load(String username, String password) async {
|
||||||
final connection = await DatabaseConnexion.initConnexion();
|
final connection = await DatabaseConnexion.initConnexion();
|
||||||
|
|
||||||
var queryResult = await connection
|
var queryResult = await connection
|
||||||
.query(
|
.query(
|
||||||
'select * from utilisateur where username = @username AND password = @password',
|
'select username from utilisateur where username = @username AND password = @password',
|
||||||
{'username': username, 'password': password})
|
{'username': username, 'password': password})
|
||||||
.toList()
|
.toList()
|
||||||
.then((result) {
|
.then((result) {
|
||||||
dev.log(result.toString());
|
dev.log(result.toString());
|
||||||
if (result.isNotEmpty) {
|
if (result.isNotEmpty) {
|
||||||
return User(username, password);
|
return User(username);
|
||||||
} else {
|
} else {
|
||||||
return User("", "");
|
return null;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.whenComplete(() {
|
.whenComplete(() {
|
@ -1,20 +1,15 @@
|
|||||||
import 'database_connexion.dart';
|
import 'database_connexion.dart';
|
||||||
import 'saver.dart';
|
import 'saver.dart';
|
||||||
import '../model/user.dart';
|
|
||||||
|
|
||||||
class DatabaseSaver extends Saver {
|
class DatabaseSaver implements Saver {
|
||||||
// Save user in the database
|
// Save user in the database
|
||||||
@override
|
@override
|
||||||
void save(User userToSave) async {
|
void save(String idDafl, String passw) async {
|
||||||
final connection = await DatabaseConnexion.initConnexion();
|
final connection = await DatabaseConnexion.initConnexion();
|
||||||
|
|
||||||
connection.execute(
|
connection.execute(
|
||||||
'insert into utilisateur (username, password) values (@username, @password)',
|
'insert into utilisateur (username, password) values (@username, @password)',
|
||||||
{
|
{'id': '', 'username': idDafl, 'password': passw}).whenComplete(() {
|
||||||
'id': '',
|
|
||||||
'username': userToSave.usernameDafl,
|
|
||||||
'password': userToSave.passwDafl
|
|
||||||
}).whenComplete(() {
|
|
||||||
connection.close();
|
connection.close();
|
||||||
});
|
});
|
||||||
}
|
}
|
@ -1,15 +1,12 @@
|
|||||||
import 'database_connexion.dart';
|
import 'database_connexion.dart';
|
||||||
import 'searcher.dart';
|
import 'searcher.dart';
|
||||||
|
|
||||||
class DatabaseSearcher extends Searcher {
|
class DatabaseSearcher implements Searcher {
|
||||||
@override
|
|
||||||
Future<bool> searchUser(String? username, String? password) async {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search an user in the database by username
|
// Search an user in the database by username
|
||||||
@override
|
@override
|
||||||
Future<bool> searchByUsername(String? username) async {
|
Future<bool> searchUser(String? username) async {
|
||||||
final connection = await DatabaseConnexion.initConnexion();
|
final connection = await DatabaseConnexion.initConnexion();
|
||||||
|
|
||||||
bool queryResult = await connection
|
bool queryResult = await connection
|
@ -0,0 +1,37 @@
|
|||||||
|
import 'package:dafl_project_flutter/services/database/database_loader.dart';
|
||||||
|
import 'package:dafl_project_flutter/services/database/database_user_modifier.dart';
|
||||||
|
import 'package:dafl_project_flutter/services/database/database_saver.dart';
|
||||||
|
import 'package:dafl_project_flutter/services/database/database_searcher.dart';
|
||||||
|
import 'package:dafl_project_flutter/services/database/loader.dart';
|
||||||
|
import 'package:dafl_project_flutter/services/database/user_modifier.dart';
|
||||||
|
import 'package:dafl_project_flutter/services/database/saver.dart';
|
||||||
|
import 'package:dafl_project_flutter/services/database/searcher.dart';
|
||||||
|
|
||||||
|
import '../../model/user.dart';
|
||||||
|
|
||||||
|
class DataBaseService {
|
||||||
|
static final Loader _loader = DatabaseLoader();
|
||||||
|
static final Searcher _searcher = DatabaseSearcher();
|
||||||
|
static final Saver _saver = DatabaseSaver();
|
||||||
|
static final UserModifier _userModifier = DatabaseUserModifier();
|
||||||
|
|
||||||
|
void save(String idDafl, String passw) {
|
||||||
|
_saver.save(idDafl, passw);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<User?> load(String username, String password) async {
|
||||||
|
return _loader.load(username, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> searchUser(String username) async {
|
||||||
|
return await _searcher.searchUser(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeUsername(String newName) {
|
||||||
|
//TODO : call database method
|
||||||
|
}
|
||||||
|
|
||||||
|
changeCurrentPassword(String newPass) {
|
||||||
|
//TODO : call database method
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
import 'package:dafl_project_flutter/services/database/user_modifier.dart';
|
||||||
|
|
||||||
|
class DatabaseUserModifier implements UserModifier {
|
||||||
|
@override
|
||||||
|
changeCurrentPassword(String userToModify, String newPass) {
|
||||||
|
// TODO: implement changeCurrentPassword
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
changeUsername(String userToModify, String newName) {
|
||||||
|
// TODO: implement changeUsername
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import '../../model/user.dart';
|
||||||
|
|
||||||
|
abstract class Loader {
|
||||||
|
Future<User?> load(String username, String password);
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
abstract class Saver {
|
||||||
|
void save(String idDafl, String passw);
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
abstract class Searcher {
|
||||||
|
Future<bool> searchUser(String? username);
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import 'package:dafl_project_flutter/model/user.dart';
|
||||||
|
|
||||||
|
abstract class UserModifier{
|
||||||
|
changeUsername(String userToModify, String newName);
|
||||||
|
|
||||||
|
changeCurrentPassword(String userToModify, String newPass);
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
|
||||||
|
import '../exceptions/http_exception.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
abstract class HttpResponseVerification {
|
||||||
|
@protected
|
||||||
|
late http.Response response;
|
||||||
|
|
||||||
|
@protected
|
||||||
|
setResponse(var value) {
|
||||||
|
if (value.statusCode >= 300) {
|
||||||
|
throw HttpException(value);
|
||||||
|
}
|
||||||
|
response = value;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
import 'package:dafl_project_flutter/model/spot.dart';
|
||||||
|
import 'package:geolocator/geolocator.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:async';
|
||||||
|
import '../../main.dart';
|
||||||
|
|
||||||
|
class Location {
|
||||||
|
static Future<List<Spot>> sendCurrentLocation() async {
|
||||||
|
Uri uri = Uri.parse(
|
||||||
|
"https://codefirst.iut.uca.fr/containers/php_script-dorianhodin/insertAndMakeListUser.php");
|
||||||
|
LocationPermission permission = await Geolocator.checkPermission();
|
||||||
|
|
||||||
|
if (permission == LocationPermission.denied) {
|
||||||
|
permission = await Geolocator.requestPermission();
|
||||||
|
|
||||||
|
if (permission == LocationPermission.deniedForever) {
|
||||||
|
//TODO : handle this case
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String actualUser = MyApp.controller.getIdDafl();
|
||||||
|
String actualSong = MyApp.controller.getCurrentMusic().id;
|
||||||
|
Position current = await Geolocator.getCurrentPosition();
|
||||||
|
|
||||||
|
http.Response response = await http.post(uri, body: {
|
||||||
|
"id": actualUser,
|
||||||
|
"latitude": current.latitude.toString(),
|
||||||
|
"longitude": current.longitude.toString(),
|
||||||
|
"idMusic": actualSong,
|
||||||
|
});
|
||||||
|
|
||||||
|
var data = jsonDecode(response.body);
|
||||||
|
Map<String, String> spotsData = {};
|
||||||
|
List<Spot> spots = [];
|
||||||
|
|
||||||
|
if (data == 2) {
|
||||||
|
return Future.error("Failed to connect, connection timeout");
|
||||||
|
} else if (data == 3) {
|
||||||
|
return Future.error("POST method failed");
|
||||||
|
} else {
|
||||||
|
data.forEach((s) => spotsData.putIfAbsent(s['user'], () => s['music']));
|
||||||
|
}
|
||||||
|
|
||||||
|
spotsData.forEach((key, value) async {
|
||||||
|
spots.add(Spot(key, await MyApp.controller.getCompleteMusic(value)));
|
||||||
|
});
|
||||||
|
return spots;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
DROP TABLE IF EXISTS Musique;
|
||||||
|
DROP TABLE IF EXISTS Matchs;
|
||||||
|
DROP TABLE IF EXISTS LikeDafl;
|
||||||
|
DROP TABLE IF EXISTS UserDafl;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE UserDafl(
|
||||||
|
idDafl INT PRIMARY KEY,
|
||||||
|
pseudo varchar(50) NOT NULL,
|
||||||
|
idSpotify varchar(150) NOT NULL,
|
||||||
|
profilPicture varchar(200) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE Musique(
|
||||||
|
idUser INT REFERENCES UserDafl(idDafl),
|
||||||
|
idMusic INT,
|
||||||
|
title varchar(50) NOT NULL,
|
||||||
|
artist varchar(50) NOT NULL,
|
||||||
|
album varchar(50) NOT NULL,
|
||||||
|
category varchar(100),
|
||||||
|
PRIMARY KEY(idUser,idMusic)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE Matchs(
|
||||||
|
idUserA INT REFERENCES UserDafl(idDafl),
|
||||||
|
idUserB INT REFERENCES UserDafl(idDafl),
|
||||||
|
dateMatch date NOT NULL,
|
||||||
|
PRIMARY KEY(idUserA,idUserB)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE LikeDafl(
|
||||||
|
idUserWhoLike INT REFERENCES UserDafl(idDafl),
|
||||||
|
idUserWhoGetLike INT REFERENCES UserDafl(idDafl),
|
||||||
|
dateLike date NOT NULL,
|
||||||
|
PRIMARY KEY(idUserWhoLike,idUserWhoGetLike)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE MessageDafl(
|
||||||
|
senderID INT NOT NULL REFERENCES UserDafl(idDafl) ,
|
||||||
|
idMessage INT PRIMARY KEY,
|
||||||
|
content varchar(500),
|
||||||
|
dateMess date NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE ConversationDafl(
|
||||||
|
idUserA INT NOT NULL REFERENCES UserDafl(idDafl),
|
||||||
|
idUserB INT NOT NULL REFERENCES UserDafl(idDafl),
|
||||||
|
idConversation INT PRIMARY KEY,
|
||||||
|
waiting BOOLEAN NOT NULL CHECK (waiting=1 OR waiting=0)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE MessToConv(
|
||||||
|
idConv INT REFERENCES Conversation(idConversation),
|
||||||
|
idMsg INT REFERENCES Message(idMessage),
|
||||||
|
PRIMARY KEY (idConv,idMsg)
|
||||||
|
);
|
@ -0,0 +1,4 @@
|
|||||||
|
FROM php:8.1-apache
|
||||||
|
RUN apt-get update && apt-get upgrade -y
|
||||||
|
RUN docker-php-ext-install mysqli
|
||||||
|
COPY ./script /var/www/html
|
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
function connection(): bool|int|mysqli
|
||||||
|
{
|
||||||
|
|
||||||
|
$username = $_ENV["USER"]; //Get the username
|
||||||
|
$host = $_ENV["HOST"]; //Get the url of the database
|
||||||
|
$password = $_ENV["PASSWORD"]; //Get the password for the user selected
|
||||||
|
$db_name = $_ENV["DATABASE"]; //Get the name of the database
|
||||||
|
|
||||||
|
try { //Try to connect to the database
|
||||||
|
|
||||||
|
return mysqli_connect($host, $username, $password,$db_name); //Connecting to database
|
||||||
|
|
||||||
|
}catch (mysqli_sql_exception) { //If the connection failed
|
||||||
|
|
||||||
|
return -1; //Send a return code as -1, so insertAndMakeListUser.php can know if the connection is successful
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
function metersBetweenTwoUser($lat1, $lng1, $lat2, $lng2): float
|
||||||
|
{
|
||||||
|
$earth_radius = 6378137; // Radius of the Earth in meters :
|
||||||
|
|
||||||
|
$rlo1 = deg2rad($lng1); //Transform the coordinate longitude1 from degree to radian
|
||||||
|
$rla1 = deg2rad($lat1); //Transform the coordinate latitude1 from degree to radian
|
||||||
|
$rlo2 = deg2rad($lng2); //Transform the coordinate longitude2 from degree to radian
|
||||||
|
$rla2 = deg2rad($lat2); //Transform the coordinate latitude2 from degree to radian
|
||||||
|
|
||||||
|
$dlo = ($rlo2 - $rlo1) / 2; //Stock in $dlo the result of the calcul : ($rlo2 - $rlo1) / 2
|
||||||
|
$dla = ($rla2 - $rla1) / 2; //Stock in $dla the result of the calcul : ($rla2 - $rla1) / 2
|
||||||
|
|
||||||
|
$a = (sin($dla) * sin($dla)) + cos($rla1) * cos($rla2) * (sin($dlo) * sin($dlo)); //Do some operations to return the distance in meters
|
||||||
|
|
||||||
|
$d = 2 * atan2(sqrt($a), sqrt(1 - $a)); //Do some operations to return the distance in meters
|
||||||
|
|
||||||
|
return round($earth_radius * $d); // Return the distance in meters between 2 GPS points
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertUserAndReturnList(): array|int
|
||||||
|
{
|
||||||
|
|
||||||
|
include "config.php";
|
||||||
|
$res = connection();
|
||||||
|
|
||||||
|
if (strcmp(gettype($res),"integer")==0) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
$query = "CREATE TABLE IF NOT EXISTS gps (
|
||||||
|
id varchar(30) PRIMARY KEY,
|
||||||
|
latitude double NOT NULL,
|
||||||
|
longitude double NOT NULL,
|
||||||
|
idMusic varchar(100) NOT NULL,
|
||||||
|
dateLog date NOT NULL
|
||||||
|
);";
|
||||||
|
mysqli_query($res, $query);
|
||||||
|
|
||||||
|
if (!empty($_POST)) { //Check if the method POST return something
|
||||||
|
|
||||||
|
$id = $_POST['id']; //Get the result of POST method
|
||||||
|
$latitude = $_POST['latitude']; //Get the result of POST method
|
||||||
|
$longitude = $_POST['longitude']; //Get the result of POST method
|
||||||
|
$idMusic = $_POST['idMusic']; //Get the result of POST method
|
||||||
|
|
||||||
|
$latitude = doubleval($latitude); //Convert a string to a double
|
||||||
|
$longitude = doubleval($longitude); //Convert a string to a double
|
||||||
|
|
||||||
|
$query = "DELETE FROM gps WHERE (TIMESTAMPDIFF(MINUTE,dateLog,NOW())>10);";
|
||||||
|
mysqli_query($res, $query);
|
||||||
|
|
||||||
|
$query = "SELECT id FROM gps WHERE id = '$id' ";
|
||||||
|
$results = mysqli_query($res, $query); //Execute the SQL command
|
||||||
|
|
||||||
|
if (empty($results->fetch_row()[0])){
|
||||||
|
|
||||||
|
$query = "INSERT INTO gps(id,latitude,longitude,idMusic,dateLog) VALUES('$id','$latitude','$longitude','$idMusic',NOW());"; //Insert into the database the new data and new information about this user
|
||||||
|
|
||||||
|
}else{
|
||||||
|
|
||||||
|
$query = "UPDATE gps SET latitude='$latitude', longitude='$longitude', idMusic='$idMusic', dateLog=NOW() WHERE id='$id'"; //Delete the actual line and replace this line with the next lines
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mysqli_query($res, $query);
|
||||||
|
|
||||||
|
$query = "SELECT * FROM gps WHERE id != '$id'"; //Browse all the database
|
||||||
|
$results = mysqli_query($res, $query); //Execute the SQL command
|
||||||
|
$listUser = []; //Set the listUser to an empty list
|
||||||
|
|
||||||
|
while ($row = $results->fetch_row()) { //For all the row in the database
|
||||||
|
|
||||||
|
$lat2 = $row[1]; //Set $lat2 to the latitude of the user who is in the actual row
|
||||||
|
$lng2 = $row[2]; //Set $lng2 to the latitude of the user who is in the actual row
|
||||||
|
$userID = $row[0]; //Set $userID to the username of the user who is in the actual row
|
||||||
|
$idMusic = $row[3]; //Set $idMusic to the id of the actual song of the user who is in the actual row
|
||||||
|
|
||||||
|
$dist = metersBetweenTwoUser($latitude, $longitude, $lat2, $lng2); //With the function meters, determinate the distance between the current user and the user who is in the actual row
|
||||||
|
|
||||||
|
if ($dist <= 100) { //If the user in the actual row is less than 100 meters away of the current user
|
||||||
|
|
||||||
|
$listUser[] = ['user' => $userID, 'music' => $idMusic]; //Add the username and the ID of the song that user who is in the actual row is listening
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $listUser; //Return an array
|
||||||
|
|
||||||
|
} else { //If the method POST return nothing
|
||||||
|
|
||||||
|
return 3; //Return a code error
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print(json_encode(insertUserAndReturnList()));
|
Loading…
Reference in new issue